com.android.ddmlib.ChunkHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ddmlib Show documentation
Show all versions of ddmlib Show documentation
Library providing APIs to talk to Android devices
/*
* 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 com.android.ddmlib.DebugPortManager.IDebugPortProvider;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* Subclass this with a class that handles one or more chunk types.
*/
abstract class ChunkHandler {
public static final int CHUNK_HEADER_LEN = 8; // 4-byte type, 4-byte len
public static final ByteOrder CHUNK_ORDER = ByteOrder.BIG_ENDIAN;
public static final int CHUNK_FAIL = type("FAIL");
ChunkHandler() {}
/**
* Client is ready. The monitor thread calls this method on all
* handlers when the client is determined to be DDM-aware (usually
* after receiving a HELO response.)
*
* The handler can use this opportunity to initialize client-side
* activity. Because there's a fair chance we'll want to send a
* message to the client, this method can throw an IOException.
*/
abstract void clientReady(Client client) throws IOException;
/**
* Client has gone away. Can be used to clean up any resources
* associated with this client connection.
*/
abstract void clientDisconnected(Client client);
/**
* Handle an incoming chunk. The data, of chunk type "type", begins
* at the start of "data" and continues to data.limit().
*
* If "isReply" is set, then "msgId" will be the ID of the request
* we sent to the client. Otherwise, it's the ID generated by the
* client for this event. Note that it's possible to receive chunks
* in reply packets for which we are not registered.
*
* The handler may not modify the contents of "data".
*/
abstract void handleChunk(Client client, int type,
ByteBuffer data, boolean isReply, int msgId);
/**
* Handle chunks not recognized by handlers. The handleChunk() method
* in sub-classes should call this if the chunk type isn't recognized.
*/
protected void handleUnknownChunk(Client client, int type,
ByteBuffer data, boolean isReply, int msgId) {
if (type == CHUNK_FAIL) {
int errorCode, msgLen;
String msg;
errorCode = data.getInt();
msgLen = data.getInt();
msg = ByteBufferUtil.getString(data, msgLen);
Log.w("ddms", "WARNING: failure code=" + errorCode + " msg=" + msg);
} else {
Log.w("ddms", "WARNING: received unknown chunk " + name(type)
+ ": len=" + data.limit() + ", reply=" + isReply
+ ", msgId=0x" + Integer.toHexString(msgId));
}
Log.w("ddms", " client " + client + ", handler " + this);
}
/**
* Utility function to copy a String out of a ByteBuffer.
*/
public static String getString(ByteBuffer buf, int len) {
return ByteBufferUtil.getString(buf, len);
}
/**
* Convert a 4-character string to a 32-bit type.
*/
static int type(String typeName) {
int val = 0;
if (typeName.length() != 4) {
Log.e("ddms", "Type name must be 4 letter long");
throw new RuntimeException("Type name must be 4 letter long");
}
for (int i = 0; i < 4; i++) {
val <<= 8;
val |= (byte) typeName.charAt(i);
}
return val;
}
/**
* Convert an integer type to a 4-character string.
*/
static String name(int type) {
char[] ascii = new char[4];
ascii[0] = (char) ((type >> 24) & 0xff);
ascii[1] = (char) ((type >> 16) & 0xff);
ascii[2] = (char) ((type >> 8) & 0xff);
ascii[3] = (char) (type & 0xff);
return new String(ascii);
}
/**
* Allocate a ByteBuffer with enough space to hold the JDWP packet
* header and one chunk header in addition to the demands of the
* chunk being created.
*
* "maxChunkLen" indicates the size of the chunk contents only.
*/
static ByteBuffer allocBuffer(int maxChunkLen) {
ByteBuffer buf =
ByteBuffer.allocate(JdwpPacket.JDWP_HEADER_LEN + 8 +maxChunkLen);
buf.order(CHUNK_ORDER);
return buf;
}
/**
* Return the slice of the JDWP packet buffer that holds just the
* chunk data.
*/
static ByteBuffer getChunkDataBuf(ByteBuffer jdwpBuf) {
ByteBuffer slice;
assert jdwpBuf.position() == 0;
jdwpBuf.position(JdwpPacket.JDWP_HEADER_LEN + CHUNK_HEADER_LEN);
slice = jdwpBuf.slice();
slice.order(CHUNK_ORDER);
jdwpBuf.position(0);
return slice;
}
/**
* Write the chunk header at the start of the chunk.
*
* Pass in the byte buffer returned by JdwpPacket.getPayload().
*/
static void finishChunkPacket(JdwpPacket packet, int type, int chunkLen) {
ByteBuffer buf = packet.getPayload();
buf.putInt(0x00, type);
buf.putInt(0x04, chunkLen);
packet.finishPacket(CHUNK_HEADER_LEN + chunkLen);
}
/**
* Check that the client is opened with the proper debugger port for the
* specified application name, and if not, reopen it.
* @param client
* @param uiThread
* @param appName
* @return
*/
protected static Client checkDebuggerPortForAppName(Client client, String appName) {
IDebugPortProvider provider = DebugPortManager.getProvider();
if (provider != null) {
Device device = client.getDeviceImpl();
int newPort = provider.getPort(device, appName);
if (newPort != IDebugPortProvider.NO_STATIC_PORT &&
newPort != client.getDebuggerListenPort()) {
AndroidDebugBridge bridge = AndroidDebugBridge.getBridge();
if (bridge != null) {
DeviceMonitor deviceMonitor = bridge.getDeviceMonitor();
if (deviceMonitor != null) {
deviceMonitor.addClientToDropAndReopen(client, newPort);
client = null;
}
}
}
}
return client;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy