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