/// <summary> /// Send a DDM packet to the client. /// /// Ideally, we can do this with a single channel write. If that doesn't /// happen, we have to prevent anybody else from writing to the channel /// until this packet completes, so we synchronize on the channel. /// /// Another goal is to avoid unnecessary buffer copies, so we write /// directly out of the JdwpPacket's ByteBuffer. /// </summary> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: void sendAndConsume(JdwpPacket packet, ChunkHandler replyHandler) throws java.io.IOException internal virtual void sendAndConsume(JdwpPacket packet, ChunkHandler replyHandler) { if (mChan == null) { // can happen for e.g. THST packets Log.v("ddms", "Not sending packet -- client is closed"); return; } if (replyHandler != null) { /* * Add the ID to the list of outstanding requests. We have to do * this before sending the packet, in case the response comes back * before our thread returns from the packet-send function. */ addRequestId(packet.id, replyHandler); } lock (mChan) { try { packet.writeAndConsume(mChan); } catch (IOException ioe) { removeRequestId(packet.id); throw ioe; } } }
/// <summary> /// Initiate the JDWP handshake. /// /// On failure, closes the socket and returns false. /// </summary> internal virtual bool sendHandshake() { Debug.Assert(mWriteBuffer.position == 0); try { // assume write buffer can hold 14 bytes JdwpPacket.putHandshake(mWriteBuffer); int expectedLen = mWriteBuffer.position; mWriteBuffer.flip(); if (mChan.write(mWriteBuffer) != expectedLen) { throw new IOException("partial handshake write"); } } catch (IOException ioe) { Log.e("ddms-client", "IO error during handshake: " + ioe.Message); mConnState = ST_ERROR; close(true); // notify return(false); } finally { mWriteBuffer.clear(); } mConnState = ST_AWAIT_SHAKE; return(true); }
/// <summary> /// Send the handshake to the debugger. We also send along any packets /// we already received from the client (usually just a VM_START event, /// if anything at all). /// </summary> private /*synchronized*/ void sendHandshake() { ByteBuffer tempBuffer = ByteBuffer.allocate(JdwpPacket.HANDSHAKE_LEN); JdwpPacket.putHandshake(tempBuffer); int expectedLength = tempBuffer.position; tempBuffer.flip(); if (mChannel.write(tempBuffer) != expectedLength) { throw new IOException("partial handshake write"); } expectedLength = mPreDataBuffer.position; if (expectedLength > 0) { Log.d("ddms", "Sending " + mPreDataBuffer.position + " bytes of saved data"); mPreDataBuffer.flip(); if (mChannel.write(mPreDataBuffer) != expectedLength) { throw new IOException("partial pre-data write"); } mPreDataBuffer.clear(); } }
/* * We have incoming data from the debugger. Forward it to the client. */ private void processDebuggerData(SelectionKey key) { Debugger dbg = (Debugger)key.attachment(); try { /* * Read pending data. */ dbg.read(); /* * See if we have a full packet in the buffer. It's possible we have * more than one packet, so we have to loop. */ JdwpPacket packet = dbg.jdwpPacket; while (packet != null) { Log.v("ddms", "Forwarding dbg req 0x" + packet.id.toHexString() + " to " + dbg.client); dbg.forwardPacketToClient(packet); packet = dbg.jdwpPacket; } } catch (IOException) { /* * Close data connection; automatically un-registers dbg from * selector. The failure could be caused by the debugger going away, * or by the client going away and failing to accept our data. * Either way, the debugger connection does not need to exist any * longer. We also need to recycle the connection to the client, so * that the VM sees the debugger disconnect. For a DDM-aware client * this won't be necessary, and we can just send a "debugger * disconnected" message. */ Log.d("ddms", "Closing connection to debugger " + dbg); dbg.closeData(); Client client = dbg.client; if (client.ddmAware) { // TODO: soft-disconnect DDM-aware clients Log.d("ddms", " (recycling client connection as well)"); // we should drop the client, but also attempt to reopen it. // This is done by the DeviceMonitor. client.deviceImpl.monitor.addClientToDropAndReopen(client, DebugPortManager.DebugPortProvider.NO_STATIC_PORT); } else { Log.d("ddms", " (recycling client connection as well)"); // we should drop the client, but also attempt to reopen it. // This is done by the DeviceMonitor. client.deviceImpl.monitor.addClientToDropAndReopen(client, DebugPortManager.DebugPortProvider.NO_STATIC_PORT); } } }
/// <summary> /// Write the chunk header at the start of the chunk. /// /// Pass in the byte buffer returned by JdwpPacket.getPayload(). /// </summary> internal static void finishChunkPacket(JdwpPacket packet, int type, int chunkLen) { ByteBuffer buf = packet.payload; buf.putInt(0x00, type); buf.putInt(0x04, chunkLen); packet.finishPacket(CHUNK_HEADER_LEN + chunkLen); }
/// <summary> /// Sends an HPDS request to the client. /// /// We will get an HPDS response when the heap dump has completed. On /// failure we get a generic failure response. /// /// This is more expensive for the device than HPDU, because the entire /// heap dump is held in RAM instead of spooled out to a temp file. On /// the other hand, permission to write to /sdcard is not required. /// </summary> /// <param name="fileName"> name of output file (on device) </param> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: public static void sendHPDS(Client client) throws java.io.IOException public static void sendHPDS(Client client) { ByteBuffer rawBuf = allocBuffer(0); JdwpPacket packet = new JdwpPacket(rawBuf); ByteBuffer buf = getChunkDataBuf(rawBuf); finishChunkPacket(packet, CHUNK_HPDS, buf.position); Log.d("ddm-heap", "Sending " + name(CHUNK_HPDS)); client.sendAndConsume(packet, mInst); }
/// <summary> /// Send an EXIT request to the client. /// </summary> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: public static void sendEXIT(Client client, int status) throws java.io.IOException public static void sendEXIT(Client client, int status) { ByteBuffer rawBuf = allocBuffer(4); JdwpPacket packet = new JdwpPacket(rawBuf); ByteBuffer buf = getChunkDataBuf(rawBuf); buf.putInt(status); finishChunkPacket(packet, CHUNK_EXIT, buf.position); Log.d("ddm-exit", "Sending " + name(CHUNK_EXIT) + ": " + status); client.sendAndConsume(packet, mInst); }
/// <summary> /// Send a MPRQ (Method PRofiling Query) request to the client. /// </summary> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: public static void sendMPRQ(Client client) throws java.io.IOException public static void sendMPRQ(Client client) { ByteBuffer rawBuf = allocBuffer(0); JdwpPacket packet = new JdwpPacket(rawBuf); ByteBuffer buf = getChunkDataBuf(rawBuf); // no data finishChunkPacket(packet, CHUNK_MPRQ, buf.position); Log.d("ddm-prof", "Sending " + name(CHUNK_MPRQ)); client.sendAndConsume(packet, mInst); }
/// <summary> /// Send a HELO request to the client. /// </summary> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: public static void sendHELO(Client client, int serverProtocolVersion) throws java.io.IOException public static void sendHELO(Client client, int serverProtocolVersion) { ByteBuffer rawBuf = allocBuffer(4); JdwpPacket packet = new JdwpPacket(rawBuf); ByteBuffer buf = getChunkDataBuf(rawBuf); buf.putInt(serverProtocolVersion); finishChunkPacket(packet, CHUNK_HELO, buf.position); Log.d("ddm-hello", "Sending " + name(CHUNK_HELO) + " ID=0x" + packet.id.toHexString()); client.sendAndConsume(packet, mInst); }
/// <summary> /// Send an HPIF (HeaP InFo) request to the client. /// </summary> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: public static void sendHPIF(Client client, int when) throws java.io.IOException public static void sendHPIF(Client client, int when) { ByteBuffer rawBuf = allocBuffer(1); JdwpPacket packet = new JdwpPacket(rawBuf); ByteBuffer buf = getChunkDataBuf(rawBuf); buf.put((byte)when); finishChunkPacket(packet, CHUNK_HPIF, buf.position); Log.d("ddm-heap", "Sending " + name(CHUNK_HPIF) + ": when=" + when); client.sendAndConsume(packet, mInst); }
/// <summary> /// An earlier request resulted in a failure. This is the expected /// response to a HELO message when talking to a non-DDM client. /// </summary> internal virtual void packetFailed(JdwpPacket reply) { if (mConnState == ST_NEED_DDM_PKT) { Log.d("ddms", "Marking " + this + " as non-DDM client"); mConnState = ST_NOT_DDM; } else if (mConnState != ST_NOT_DDM) { Log.w("ddms", "WEIRD: got JDWP failure packet on DDM req"); } }
/// <summary> /// Sends a REAE (REcent Allocation Enable) request to the client. /// </summary> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: public static void sendREAE(Client client, boolean enable) throws java.io.IOException public static void sendREAE(Client client, bool enable) { ByteBuffer rawBuf = allocBuffer(1); JdwpPacket packet = new JdwpPacket(rawBuf); ByteBuffer buf = getChunkDataBuf(rawBuf); buf.put((byte)(enable ? 1 : 0)); finishChunkPacket(packet, CHUNK_REAE, buf.position); Log.d("ddm-heap", "Sending " + name(CHUNK_REAE) + ": " + enable); client.sendAndConsume(packet, mInst); }
/// <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); }
/* * Send a THST request to the specified client. */ //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: private static void sendTHST(Client client) throws java.io.IOException private static void sendTHST(Client client) { ByteBuffer rawBuf = allocBuffer(0); JdwpPacket packet = new JdwpPacket(rawBuf); ByteBuffer buf = getChunkDataBuf(rawBuf); // nothing much to say finishChunkPacket(packet, CHUNK_THST, buf.position); Log.d("ddm-thread", "Sending " + name(CHUNK_THST)); client.sendAndConsume(packet, mInst); }
/// <summary> /// Sends an HPDU request to the client. /// /// We will get an HPDU response when the heap dump has completed. On /// failure we get a generic failure response. /// </summary> /// <param name="fileName"> name of output file (on device) </param> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: public static void sendHPDU(Client client, String fileName) throws java.io.IOException public static void sendHPDU(Client client, string fileName) { ByteBuffer rawBuf = allocBuffer(4 + fileName.Length * 2); JdwpPacket packet = new JdwpPacket(rawBuf); ByteBuffer buf = getChunkDataBuf(rawBuf); buf.putInt(fileName.Length); putString(buf, fileName); finishChunkPacket(packet, CHUNK_HPDU, buf.position); Log.d("ddm-heap", "Sending " + name(CHUNK_HPDU) + " '" + fileName + "'"); client.sendAndConsume(packet, mInst); client.clientData.pendingHprofDump = fileName; }
/// <summary> /// Forward the packet to the debugger (if still connected to one). /// /// Consumes the packet. /// </summary> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: void forwardPacketToDebugger(JdwpPacket packet) throws java.io.IOException internal virtual void forwardPacketToDebugger(JdwpPacket packet) { Debugger dbg = mDebugger; if (dbg == null) { Log.d("ddms", "Discarding packet"); packet.consume(); } else { dbg.sendAndConsume(packet); } }
/// <summary> /// Send a MPSS (Method Profiling Streaming Start) request to the client. /// /// The arguments to this method will eventually be passed to /// android.os.Debug.startMethodTracing() on the device. /// </summary> /// <param name="bufferSize"> is the desired buffer size in bytes (8MB is good) </param> /// <param name="flags"> see startMethodTracing() docs; use 0 for default behavior </param> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: public static void sendMPSS(Client client, int bufferSize, int flags) throws java.io.IOException public static void sendMPSS(Client client, int bufferSize, int flags) { ByteBuffer rawBuf = allocBuffer(2 * 4); JdwpPacket packet = new JdwpPacket(rawBuf); ByteBuffer buf = getChunkDataBuf(rawBuf); buf.putInt(bufferSize); buf.putInt(flags); finishChunkPacket(packet, CHUNK_MPSS, buf.position); Log.d("ddm-prof", "Sending " + name(CHUNK_MPSS) + "', size=" + bufferSize + ", flags=" + flags); client.sendAndConsume(packet, mInst); // send a status query. this ensure that the status is properly updated if for some // reason starting the tracing failed. sendMPRQ(client); }
/* * Process an incoming DDM packet. If this is a reply to an earlier request, * "handler" will be set to the handler responsible for the original * request. The spec allows a JDWP message to include multiple DDM chunks. */ private void callHandler(Client client, JdwpPacket packet, ChunkHandler handler) { // on first DDM packet received, broadcast a "ready" message if (!client.ddmSeen()) { broadcast(CLIENT_READY, client); } ByteBuffer buf = packet.payload; int type, length; bool reply = true; type = buf.getInt(); length = buf.getInt(); if (handler == null) { // not a reply, figure out who wants it lock (mHandlerMap) { handler = mHandlerMap[type]; reply = false; } } if (handler == null) { Log.w("ddms", "Received unsupported chunk type " + ChunkHandler.name(type) + " (len=" + length + ")"); } else { Log.d("ddms", "Calling handler for " + ChunkHandler.name(type) + " [" + handler + "] (len=" + length + ")"); ByteBuffer ibuf = buf.slice(); ByteBuffer roBuf = ibuf.asReadOnlyBuffer(); // enforce R/O roBuf.order = ChunkHandler.CHUNK_ORDER; // do the handling of the chunk synchronized on the client list // to be sure there's no concurrency issue when we look for HOME // in hasApp() lock (mClientList) { handler.handleChunk(client, type, roBuf, reply, packet.id); } } }
/// <summary> /// Send a THEN (THread notification ENable) request to the client. /// </summary> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: public static void sendTHEN(Client client, boolean enable) throws java.io.IOException public static void sendTHEN(Client client, bool enable) { ByteBuffer rawBuf = allocBuffer(1); JdwpPacket packet = new JdwpPacket(rawBuf); ByteBuffer buf = getChunkDataBuf(rawBuf); if (enable) { buf.put(1); } else { buf.put(0); } finishChunkPacket(packet, CHUNK_THEN, buf.position); Log.d("ddm-thread", "Sending " + name(CHUNK_THEN) + ": " + enable); client.sendAndConsume(packet, mInst); }
/// <summary> /// Send a packet to the debugger. /// /// Ideally, we can do this with a single channel write. If that doesn't /// happen, we have to prevent anybody else from writing to the channel /// until this packet completes, so we synchronize on the channel. /// /// Another goal is to avoid unnecessary buffer copies, so we write /// directly out of the JdwpPacket's ByteBuffer. /// /// We must synchronize on "mChannel" before writing to it. We want to /// coordinate the buffered data with mChannel creation, so this whole /// method is synchronized. /// </summary> /*lock*/ internal void sendAndConsume(JdwpPacket packet) { if (mChannel == null) { /* * Buffer this up so we can send it to the debugger when it * finally does connect. This is essential because the VM_START * message might be telling the debugger that the VM is * suspended. The alternative approach would be for us to * capture and interpret VM_START and send it later if we * didn't choose to un-suspend the VM for our own purposes. */ Log.d("ddms", "Saving packet 0x" + packet.id.toHexString()); packet.movePacket(mPreDataBuffer); } else { packet.writeAndConsume(mChannel); } }
/// <summary> /// Send a STKL (STacK List) request to the client. The VM will suspend /// the target thread, obtain its stack, and return it. If the thread /// is no longer running, a failure result will be returned. /// </summary> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: public static void sendSTKL(Client client, int threadId) throws java.io.IOException public static void sendSTKL(Client client, int threadId) { /* * if (false) * { * Log.d("ddm-thread", "would send STKL " + threadId); * return; * } */ ByteBuffer rawBuf = allocBuffer(4); JdwpPacket packet = new JdwpPacket(rawBuf); ByteBuffer buf = getChunkDataBuf(rawBuf); buf.putInt(threadId); finishChunkPacket(packet, CHUNK_STKL, buf.position); Log.d("ddm-thread", "Sending " + name(CHUNK_STKL) + ": " + threadId); client.sendAndConsume(packet, mInst); }
/// <summary> /// Send a MPRS (Method PRofiling Start) request to the client. /// /// The arguments to this method will eventually be passed to /// android.os.Debug.startMethodTracing() on the device. /// </summary> /// <param name="fileName"> is the name of the file to which profiling data /// will be written (on the device); it will have <seealso cref="DdmConstants#DOT_TRACE"/> /// appended if necessary </param> /// <param name="bufferSize"> is the desired buffer size in bytes (8MB is good) </param> /// <param name="flags"> see startMethodTracing() docs; use 0 for default behavior </param> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: public static void sendMPRS(Client client, String fileName, int bufferSize, int flags) throws java.io.IOException public static void sendMPRS(Client client, string fileName, int bufferSize, int flags) { ByteBuffer rawBuf = allocBuffer(3 * 4 + fileName.Length * 2); JdwpPacket packet = new JdwpPacket(rawBuf); ByteBuffer buf = getChunkDataBuf(rawBuf); buf.putInt(bufferSize); buf.putInt(flags); buf.putInt(fileName.Length); putString(buf, fileName); finishChunkPacket(packet, CHUNK_MPRS, buf.position); Log.d("ddm-prof", "Sending " + name(CHUNK_MPRS) + " '" + fileName + "', size=" + bufferSize + ", flags=" + flags); client.sendAndConsume(packet, mInst); // record the filename we asked for. client.clientData.pendingMethodProfiling = fileName; // send a status query. this ensure that the status is properly updated if for some // reason starting the tracing failed. sendMPRQ(client); }
/// <summary> /// Send an NHGT (Native Thread GeT) request to the client. /// </summary> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: public static void sendNHGT(Client client) throws java.io.IOException public static void sendNHGT(Client client) { 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.sendAndConsume(packet, mInst); rawBuf = allocBuffer(2); packet = new JdwpPacket(rawBuf); buf = getChunkDataBuf(rawBuf); buf.put(HandleHeap.WHEN_DISABLE); buf.put(HandleHeap.WHAT_OBJ); finishChunkPacket(packet, CHUNK_NHSG, buf.position); Log.d("ddm-nativeheap", "Sending " + name(CHUNK_NHSG)); client.sendAndConsume(packet, mInst); }
/// <summary> /// Forward a packet to the client. /// /// "mClient" will never be null, though it's possible that the channel /// in the client has closed and our send attempt will fail. /// /// Consumes the packet. /// </summary> internal void forwardPacketToClient(JdwpPacket packet) { mClient.sendAndConsume(packet); }
/// <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> /// Sends an HPSG (HeaP SeGment) request to the client. /// </summary> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: public static void sendHPSG(Client client, int when, int what) throws java.io.IOException public static void sendHPSG(Client client, int when, int what) { ByteBuffer rawBuf = allocBuffer(2); JdwpPacket packet = new JdwpPacket(rawBuf); ByteBuffer buf = getChunkDataBuf(rawBuf); buf.put((byte)when); buf.put((byte)what); finishChunkPacket(packet, CHUNK_HPSG, buf.position); Log.d("ddm-heap", "Sending " + name(CHUNK_HPSG) + ": when=" + when + ", what=" + what); client.sendAndConsume(packet, mInst); }
/// <summary> /// Send a non-DDM packet to the client. /// /// Equivalent to sendAndConsume(packet, null). /// </summary> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: void sendAndConsume(JdwpPacket packet) throws java.io.IOException internal virtual void sendAndConsume(JdwpPacket packet) { sendAndConsume(packet, null); }
/// <summary> /// Send a FEAT request to the client. /// </summary> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: public static void sendFEAT(Client client) throws java.io.IOException public static void sendFEAT(Client client) { ByteBuffer rawBuf = allocBuffer(0); JdwpPacket packet = new JdwpPacket(rawBuf); ByteBuffer buf = getChunkDataBuf(rawBuf); // no data finishChunkPacket(packet, CHUNK_FEAT, buf.position); Log.d("ddm-heap", "Sending " + name(CHUNK_FEAT)); client.sendAndConsume(packet, mInst); }
/* * Something happened. Figure out what. */ private void processClientActivity(SelectionKey key) { Client client = (Client)key.attachment(); try { if (key.readable == false || key.valid == false) { Log.d("ddms", "Invalid key from " + client + ". Dropping client."); dropClient(client, true); // notify return; } client.read(); /* * See if we have a full packet in the buffer. It's possible we have * more than one packet, so we have to loop. */ JdwpPacket packet = client.jdwpPacket; while (packet != null) { if (packet.ddmPacket) { // unsolicited DDM request - hand it off Debug.Assert(!packet.reply); callHandler(client, packet, null); packet.consume(); } else if (packet.reply && client.isResponseToUs(packet.id) != null) { // reply to earlier DDM request ChunkHandler handler = client.isResponseToUs(packet.id); if (packet.error) { client.packetFailed(packet); } else if (packet.empty) { Log.d("ddms", "Got empty reply for 0x" + packet.id.toHexString() + " from " + client); } else { callHandler(client, packet, handler); } packet.consume(); client.removeRequestId(packet.id); } else { Log.v("ddms", "Forwarding client " + (packet.reply ? "reply" : "event") + " 0x" + packet.id.toHexString() + " to " + client.debugger); client.forwardPacketToDebugger(packet); } // find next packet = client.jdwpPacket; } } catch (CancelledKeyException) { // key was canceled probably due to a disconnected client before we could // read stuff coming from the client, so we drop it. dropClient(client, true); // notify } catch (IOException) { // something closed down, no need to print anything. The client is simply dropped. dropClient(client, true); // notify } catch (Exception ex) { Log.e("ddms", ex); /* close the client; automatically un-registers from selector */ dropClient(client, true); // notify if (ex is OverflowException) { Log.w("ddms", "Client data packet exceeded maximum buffer size " + client); } else { // don't know what this is, display it Log.e("ddms", ex); } } }
/// <summary> /// Send a STKL (STacK List) request to the client. The VM will suspend /// the target thread, obtain its stack, and return it. If the thread /// is no longer running, a failure result will be returned. /// </summary> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: public static void sendSTKL(Client client, int threadId) throws java.io.IOException public static void sendSTKL(Client client, int threadId) { /* if (false) { Log.d("ddm-thread", "would send STKL " + threadId); return; } */ ByteBuffer rawBuf = allocBuffer(4); JdwpPacket packet = new JdwpPacket(rawBuf); ByteBuffer buf = getChunkDataBuf(rawBuf); buf.putInt(threadId); finishChunkPacket(packet, CHUNK_STKL, buf.position); Log.d("ddm-thread", "Sending " + name(CHUNK_STKL) + ": " + threadId); client.sendAndConsume(packet, mInst); }