| /* |
| * Copyright (C) 2007 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.ddmlib; |
| |
| import java.io.IOException; |
| import java.nio.BufferUnderflowException; |
| import java.nio.ByteBuffer; |
| |
| /** |
| * Handle the "hello" chunk (HELO) and feature discovery. |
| */ |
| final class HandleHello extends ChunkHandler { |
| |
| public static final int CHUNK_HELO = ChunkHandler.type("HELO"); |
| public static final int CHUNK_FEAT = ChunkHandler.type("FEAT"); |
| |
| private static final HandleHello mInst = new HandleHello(); |
| |
| private HandleHello() {} |
| |
| /** |
| * Register for the packets we expect to get from the client. |
| */ |
| public static void register(MonitorThread mt) { |
| mt.registerChunkHandler(CHUNK_HELO, mInst); |
| } |
| |
| /** |
| * Client is ready. |
| */ |
| @Override |
| public void clientReady(Client client) throws IOException { |
| Log.d("ddm-hello", "Now ready: " + client); |
| } |
| |
| /** |
| * Client went away. |
| */ |
| @Override |
| public void clientDisconnected(Client client) { |
| Log.d("ddm-hello", "Now disconnected: " + client); |
| } |
| |
| /** |
| * Sends HELLO-type commands to the VM after a good handshake. |
| * @param client |
| * @param serverProtocolVersion |
| * @throws IOException |
| */ |
| public static void sendHelloCommands(Client client, int serverProtocolVersion) |
| throws IOException { |
| sendHELO(client, serverProtocolVersion); |
| sendFEAT(client); |
| HandleProfiling.sendMPRQ(client); |
| } |
| |
| /** |
| * Chunk handler entry point. |
| */ |
| @Override |
| public void handleChunk(Client client, int type, ByteBuffer data, boolean isReply, int msgId) { |
| |
| Log.d("ddm-hello", "handling " + ChunkHandler.name(type)); |
| |
| if (type == CHUNK_HELO) { |
| assert isReply; |
| handleHELO(client, data); |
| } else if (type == CHUNK_FEAT) { |
| handleFEAT(client, data); |
| } else { |
| handleUnknownChunk(client, type, data, isReply, msgId); |
| } |
| } |
| |
| /* |
| * Handle a reply to our HELO message. |
| */ |
| private static void handleHELO(Client client, ByteBuffer data) { |
| int version, pid, vmIdentLen, appNameLen; |
| String vmIdent, appName; |
| |
| version = data.getInt(); |
| pid = data.getInt(); |
| vmIdentLen = data.getInt(); |
| appNameLen = data.getInt(); |
| |
| vmIdent = ByteBufferUtil.getString(data, vmIdentLen); |
| appName = ByteBufferUtil.getString(data, appNameLen); |
| |
| // Newer devices send user id in the APNM packet. |
| int userId = -1; |
| boolean validUserId = false; |
| if (data.hasRemaining()) { |
| try { |
| userId = data.getInt(); |
| validUserId = true; |
| } catch (BufferUnderflowException e) { |
| // five integers + two utf-16 strings |
| int expectedPacketLength = 20 + appNameLen * 2 + vmIdentLen * 2; |
| |
| Log.e("ddm-hello", "Insufficient data in HELO chunk to retrieve user id."); |
| Log.e("ddm-hello", "Actual chunk length: " + data.capacity()); |
| Log.e("ddm-hello", "Expected chunk length: " + expectedPacketLength); |
| } |
| } |
| |
| // check if the VM has reported information about the ABI |
| boolean validAbi = false; |
| String abi = null; |
| if (data.hasRemaining()) { |
| try { |
| int abiLength = data.getInt(); |
| abi = ByteBufferUtil.getString(data, abiLength); |
| validAbi = true; |
| } catch (BufferUnderflowException e) { |
| Log.e("ddm-hello", "Insufficient data in HELO chunk to retrieve ABI."); |
| } |
| } |
| |
| boolean hasJvmFlags = false; |
| String jvmFlags = null; |
| if (data.hasRemaining()) { |
| try { |
| int jvmFlagsLength = data.getInt(); |
| jvmFlags = ByteBufferUtil.getString(data, jvmFlagsLength); |
| hasJvmFlags = true; |
| } catch (BufferUnderflowException e) { |
| Log.e("ddm-hello", "Insufficient data in HELO chunk to retrieve JVM flags"); |
| } |
| } |
| |
| Log.d("ddm-hello", "HELO: v=" + version + ", pid=" + pid |
| + ", vm='" + vmIdent + "', app='" + appName + "'"); |
| |
| ClientData cd = client.getClientData(); |
| |
| if (cd.getPid() == pid) { |
| cd.setVmIdentifier(vmIdent); |
| cd.setClientDescription(appName); |
| cd.isDdmAware(true); |
| |
| if (validUserId) { |
| cd.setUserId(userId); |
| } |
| |
| if (validAbi) { |
| cd.setAbi(abi); |
| } |
| |
| if (hasJvmFlags) { |
| cd.setJvmFlags(jvmFlags); |
| } |
| } else { |
| Log.e("ddm-hello", "Received pid (" + pid + ") does not match client pid (" |
| + cd.getPid() + ")"); |
| } |
| |
| client = checkDebuggerPortForAppName(client, appName); |
| |
| if (client != null) { |
| client.update(Client.CHANGE_NAME); |
| } |
| } |
| |
| |
| /** |
| * Send a HELO request to the client. |
| */ |
| public static void sendHELO(Client client, int serverProtocolVersion) |
| throws IOException |
| { |
| 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" + Integer.toHexString(packet.getId())); |
| client.sendAndConsume(packet, mInst); |
| } |
| |
| /** |
| * Handle a reply to our FEAT request. |
| */ |
| private static void handleFEAT(Client client, ByteBuffer data) { |
| int featureCount; |
| int i; |
| |
| featureCount = data.getInt(); |
| for (i = 0; i < featureCount; i++) { |
| int len = data.getInt(); |
| String feature = ByteBufferUtil.getString(data, len); |
| client.getClientData().addFeature(feature); |
| |
| Log.d("ddm-hello", "Feature: " + feature); |
| } |
| } |
| |
| /** |
| * Send a FEAT request to the client. |
| */ |
| public static void sendFEAT(Client client) throws IOException { |
| 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); |
| } |
| } |
| |