155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project/* 255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Copyright (C) 2007 The Android Open Source Project 355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * 455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * you may not use this file except in compliance with the License. 655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * You may obtain a copy of the License at 755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * 855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * 1055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software 1155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 1255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * See the License for the specific language governing permissions and 1455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * limitations under the License. 1555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project */ 1655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 1755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Projectpackage com.android.ddmlib; 1855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 19bcf38645bef192b380f0d338b263aea075cd1aebXavier Ducrohetimport com.android.ddmlib.ClientData.DebuggerStatus; 20bcf38645bef192b380f0d338b263aea075cd1aebXavier Ducrohet 2155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Projectimport java.io.IOException; 2255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Projectimport java.net.InetAddress; 2355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Projectimport java.net.InetSocketAddress; 2455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Projectimport java.nio.BufferOverflowException; 2555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Projectimport java.nio.ByteBuffer; 2655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Projectimport java.nio.channels.SelectionKey; 2755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Projectimport java.nio.channels.Selector; 2855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Projectimport java.nio.channels.ServerSocketChannel; 2955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Projectimport java.nio.channels.SocketChannel; 3055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 3155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project/** 3255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * This represents a pending or established connection with a JDWP debugger. 3355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project */ 3455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Projectclass Debugger { 3555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 3655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project /* 3755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Messages from the debugger should be pretty small; may not even 3855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * need an expanding-buffer implementation for this. 3955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project */ 4055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project private static final int INITIAL_BUF_SIZE = 1 * 1024; 4155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project private static final int MAX_BUF_SIZE = 32 * 1024; 4255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project private ByteBuffer mReadBuffer; 4355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 4455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project private static final int PRE_DATA_BUF_SIZE = 256; 4555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project private ByteBuffer mPreDataBuffer; 4655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 4755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project /* connection state */ 4855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project private int mConnState; 4955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project private static final int ST_NOT_CONNECTED = 1; 5055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project private static final int ST_AWAIT_SHAKE = 2; 5155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project private static final int ST_READY = 3; 5255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 5355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project /* peer */ 5455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project private Client mClient; // client we're forwarding to/from 5555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project private int mListenPort; // listen to me 5655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project private ServerSocketChannel mListenChannel; 5755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 5855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project /* this goes up and down; synchronize methods that access the field */ 5955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project private SocketChannel mChannel; 6055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 6155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project /** 6255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Create a new Debugger object, configured to listen for connections 6355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * on a specific port. 6455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project */ 6555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project Debugger(Client client, int listenPort) throws IOException { 6655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 6755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project mClient = client; 6855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project mListenPort = listenPort; 6955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 7055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project mListenChannel = ServerSocketChannel.open(); 7155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project mListenChannel.configureBlocking(false); // required for Selector 7255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 7355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project InetSocketAddress addr = new InetSocketAddress( 7423da069e4f407df1b06e7db2324e3247496abe3dTor Norbye InetAddress.getByName("localhost"), //$NON-NLS-1$ 7555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project listenPort); 7655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project mListenChannel.socket().setReuseAddress(true); // enable SO_REUSEADDR 7755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project mListenChannel.socket().bind(addr); 7855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 7955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project mReadBuffer = ByteBuffer.allocate(INITIAL_BUF_SIZE); 8055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project mPreDataBuffer = ByteBuffer.allocate(PRE_DATA_BUF_SIZE); 8155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project mConnState = ST_NOT_CONNECTED; 8255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 837ab724a2d101fb390a2622c3f0c90405c91f78fbXavier Ducrohet Log.d("ddms", "Created: " + this.toString()); 8455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } 8555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 8655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project /** 8755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Returns "true" if a debugger is currently attached to us. 8855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project */ 8955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project boolean isDebuggerAttached() { 9055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project return mChannel != null; 9155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } 9255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 9355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project /** 9455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Represent the Debugger as a string. 9555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project */ 9655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project @Override 9755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project public String toString() { 9855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project // mChannel != null means we have connection, ST_READY means it's going 9955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project return "[Debugger " + mListenPort + "-->" + mClient.getClientData().getPid() 10055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project + ((mConnState != ST_READY) ? " inactive]" : " active]"); 10155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } 10255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 10355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project /** 10455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Register the debugger's listen socket with the Selector. 10555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project */ 10655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project void registerListener(Selector sel) throws IOException { 10755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project mListenChannel.register(sel, SelectionKey.OP_ACCEPT, this); 10855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } 10955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 11055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project /** 11155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Return the Client being debugged. 11255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project */ 11355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project Client getClient() { 11455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project return mClient; 11555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } 11655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 11755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project /** 11855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Accept a new connection, but only if we don't already have one. 11955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * 12055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Must be synchronized with other uses of mChannel and mPreBuffer. 12155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * 12255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Returns "null" if we're already talking to somebody. 12355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project */ 12455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project synchronized SocketChannel accept() throws IOException { 12555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project return accept(mListenChannel); 12655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } 12755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 12855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project /** 12955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Accept a new connection from the specified listen channel. This 13055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * is so we can listen on a dedicated port for the "current" client, 13155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * where "current" is constantly in flux. 13255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * 13355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Must be synchronized with other uses of mChannel and mPreBuffer. 13455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * 13555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Returns "null" if we're already talking to somebody. 13655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project */ 13755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project synchronized SocketChannel accept(ServerSocketChannel listenChan) 13855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project throws IOException { 13955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 14055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project if (listenChan != null) { 14155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project SocketChannel newChan; 1427ab724a2d101fb390a2622c3f0c90405c91f78fbXavier Ducrohet 14355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project newChan = listenChan.accept(); 14455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project if (mChannel != null) { 14555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project Log.w("ddms", "debugger already talking to " + mClient 14655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project + " on " + mListenPort); 14755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project newChan.close(); 14855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project return null; 14955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } 15055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project mChannel = newChan; 15155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project mChannel.configureBlocking(false); // required for Selector 15255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project mConnState = ST_AWAIT_SHAKE; 15355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project return mChannel; 15455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } 1557ab724a2d101fb390a2622c3f0c90405c91f78fbXavier Ducrohet 15655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project return null; 15755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } 15855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 15955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project /** 16055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Close the data connection only. 16155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project */ 16255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project synchronized void closeData() { 16355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project try { 16455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project if (mChannel != null) { 16555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project mChannel.close(); 16655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project mChannel = null; 16755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project mConnState = ST_NOT_CONNECTED; 16855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 16955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project ClientData cd = mClient.getClientData(); 170bcf38645bef192b380f0d338b263aea075cd1aebXavier Ducrohet cd.setDebuggerConnectionStatus(DebuggerStatus.DEFAULT); 171bcf38645bef192b380f0d338b263aea075cd1aebXavier Ducrohet mClient.update(Client.CHANGE_DEBUGGER_STATUS); 17255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } 17355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } catch (IOException ioe) { 17455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project Log.w("ddms", "Failed to close data " + this); 17555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } 17655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } 17755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 17855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project /** 17955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Close the socket that's listening for new connections and (if 18055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * we're connected) the debugger data socket. 18155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project */ 18255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project synchronized void close() { 18355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project try { 18455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project if (mListenChannel != null) { 18555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project mListenChannel.close(); 18655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } 18755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project mListenChannel = null; 18855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project closeData(); 18955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } catch (IOException ioe) { 19055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project Log.w("ddms", "Failed to close listener " + this); 19155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } 19255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } 19355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 19455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project // TODO: ?? add a finalizer that verifies the channel was closed 19555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 19655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project /** 19755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Read data from our channel. 19855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * 19955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * This is called when data is known to be available, and we don't yet 20055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * have a full packet in the buffer. If the buffer is at capacity, 20155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * expand it. 20255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project */ 20355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project void read() throws IOException { 20455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project int count; 20555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 20655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project if (mReadBuffer.position() == mReadBuffer.capacity()) { 20755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project if (mReadBuffer.capacity() * 2 > MAX_BUF_SIZE) { 20855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project throw new BufferOverflowException(); 20955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } 21055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project Log.d("ddms", "Expanding read buffer to " 21155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project + mReadBuffer.capacity() * 2); 21255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 21355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project ByteBuffer newBuffer = 21455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project ByteBuffer.allocate(mReadBuffer.capacity() * 2); 21555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project mReadBuffer.position(0); 21655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project newBuffer.put(mReadBuffer); // leaves "position" at end 21755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 21855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project mReadBuffer = newBuffer; 21955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } 22055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 22155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project count = mChannel.read(mReadBuffer); 22255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project Log.v("ddms", "Read " + count + " bytes from " + this); 22355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project if (count < 0) throw new IOException("read failed"); 22455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } 22555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 22655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project /** 22755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Return information for the first full JDWP packet in the buffer. 22855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * 22955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * If we don't yet have a full packet, return null. 23055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * 23155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * If we haven't yet received the JDWP handshake, we watch for it here 23255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * and consume it without admitting to have done so. We also send 23355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * the handshake response to the debugger, along with any pending 23455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * pre-connection data, which is why this can throw an IOException. 23555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project */ 23655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project JdwpPacket getJdwpPacket() throws IOException { 23755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project /* 23855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * On entry, the data starts at offset 0 and ends at "position". 23955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * "limit" is set to the buffer capacity. 24055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project */ 24155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project if (mConnState == ST_AWAIT_SHAKE) { 24255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project int result; 24355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 24455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project result = JdwpPacket.findHandshake(mReadBuffer); 24555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project //Log.v("ddms", "findHand: " + result); 24655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project switch (result) { 24755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project case JdwpPacket.HANDSHAKE_GOOD: 2487ab724a2d101fb390a2622c3f0c90405c91f78fbXavier Ducrohet Log.d("ddms", "Good handshake from debugger"); 24955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project JdwpPacket.consumeHandshake(mReadBuffer); 25055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project sendHandshake(); 25155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project mConnState = ST_READY; 25255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 25355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project ClientData cd = mClient.getClientData(); 254bcf38645bef192b380f0d338b263aea075cd1aebXavier Ducrohet cd.setDebuggerConnectionStatus(DebuggerStatus.ATTACHED); 255bcf38645bef192b380f0d338b263aea075cd1aebXavier Ducrohet mClient.update(Client.CHANGE_DEBUGGER_STATUS); 25655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 25755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project // see if we have another packet in the buffer 25855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project return getJdwpPacket(); 25955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project case JdwpPacket.HANDSHAKE_BAD: 26055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project // not a debugger, throw an exception so we drop the line 2617ab724a2d101fb390a2622c3f0c90405c91f78fbXavier Ducrohet Log.d("ddms", "Bad handshake from debugger"); 26255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project throw new IOException("bad handshake"); 26355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project case JdwpPacket.HANDSHAKE_NOTYET: 26455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project break; 26555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project default: 26655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project Log.e("ddms", "Unknown packet while waiting for client handshake"); 26755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } 26855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project return null; 26955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } else if (mConnState == ST_READY) { 27055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project if (mReadBuffer.position() != 0) { 27155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project Log.v("ddms", "Checking " + mReadBuffer.position() + " bytes"); 27255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } 27355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project return JdwpPacket.findPacket(mReadBuffer); 27455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } else { 27555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project Log.e("ddms", "Receiving data in state = " + mConnState); 27655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } 2777ab724a2d101fb390a2622c3f0c90405c91f78fbXavier Ducrohet 27855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project return null; 27955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } 28055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 28155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project /** 28255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Forward a packet to the client. 28355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * 28455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * "mClient" will never be null, though it's possible that the channel 28555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * in the client has closed and our send attempt will fail. 28655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * 28755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Consumes the packet. 28855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project */ 28955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project void forwardPacketToClient(JdwpPacket packet) throws IOException { 29055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project mClient.sendAndConsume(packet); 29155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } 29255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 29355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project /** 29455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Send the handshake to the debugger. We also send along any packets 29555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * we already received from the client (usually just a VM_START event, 29655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * if anything at all). 29755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project */ 29855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project private synchronized void sendHandshake() throws IOException { 29955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project ByteBuffer tempBuffer = ByteBuffer.allocate(JdwpPacket.HANDSHAKE_LEN); 30055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project JdwpPacket.putHandshake(tempBuffer); 30155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project int expectedLength = tempBuffer.position(); 30255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project tempBuffer.flip(); 30355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project if (mChannel.write(tempBuffer) != expectedLength) { 30455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project throw new IOException("partial handshake write"); 30555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } 30655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 30755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project expectedLength = mPreDataBuffer.position(); 30855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project if (expectedLength > 0) { 30955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project Log.d("ddms", "Sending " + mPreDataBuffer.position() 31055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project + " bytes of saved data"); 31155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project mPreDataBuffer.flip(); 31255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project if (mChannel.write(mPreDataBuffer) != expectedLength) { 31355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project throw new IOException("partial pre-data write"); 31455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } 31555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project mPreDataBuffer.clear(); 31655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } 31755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } 31855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 31955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project /** 32055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Send a packet to the debugger. 32155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * 32255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Ideally, we can do this with a single channel write. If that doesn't 32355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * happen, we have to prevent anybody else from writing to the channel 32455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * until this packet completes, so we synchronize on the channel. 32555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * 32655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Another goal is to avoid unnecessary buffer copies, so we write 32755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * directly out of the JdwpPacket's ByteBuffer. 32855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * 32955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * We must synchronize on "mChannel" before writing to it. We want to 33055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * coordinate the buffered data with mChannel creation, so this whole 33155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * method is synchronized. 33255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project */ 33355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project synchronized void sendAndConsume(JdwpPacket packet) 33455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project throws IOException { 33555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 33655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project if (mChannel == null) { 33755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project /* 33855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Buffer this up so we can send it to the debugger when it 33955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * finally does connect. This is essential because the VM_START 34055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * message might be telling the debugger that the VM is 34155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * suspended. The alternative approach would be for us to 34255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * capture and interpret VM_START and send it later if we 34355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * didn't choose to un-suspend the VM for our own purposes. 34455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project */ 34555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project Log.d("ddms", "Saving packet 0x" 34655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project + Integer.toHexString(packet.getId())); 34755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project packet.movePacket(mPreDataBuffer); 34855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } else { 34955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project packet.writeAndConsume(mChannel); 35055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } 35155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project } 35255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project} 35355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project 354