DdmHandleViewDebugpublic class DdmHandleViewDebug extends org.apache.harmony.dalvik.ddmc.ChunkHandler Handle various requests related to profiling / debugging of the view system.
Support for these features are advertised via {@link DdmHandleHello}. |
Fields Summary |
---|
public static final int | CHUNK_VUGLEnable/Disable tracing of OpenGL calls. | private static final int | CHUNK_VULWList {@link ViewRootImpl}'s of this process. | private static final int | CHUNK_VURTOperation on view root, first parameter in packet should be one of VURT_* constants | private static final int | VURT_DUMP_HIERARCHYDump view hierarchy. | private static final int | VURT_CAPTURE_LAYERSCapture View Layers. | private static final int | VURT_DUMP_THEMEDump View Theme. | private static final int | CHUNK_VUOPGeneric View Operation, first parameter in the packet should be one of the
VUOP_* constants below. | private static final int | VUOP_CAPTURE_VIEWCapture View. | private static final int | VUOP_DUMP_DISPLAYLISTObtain the Display List corresponding to the view. | private static final int | VUOP_PROFILE_VIEWProfile a view. | private static final int | VUOP_INVOKE_VIEW_METHODInvoke a method on the view. | private static final int | VUOP_SET_LAYOUT_PARAMETERSet layout parameter. | private static final int | ERR_INVALID_OPError code indicating operation specified in chunk is invalid. | private static final int | ERR_INVALID_PARAMError code indicating that the parameters are invalid. | private static final int | ERR_EXCEPTIONError code indicating an exception while performing operation. | private static final String | TAG | private static final DdmHandleViewDebug | sInstance |
Constructors Summary |
---|
private DdmHandleViewDebug()singleton, do not instantiate.
|
Methods Summary |
---|
private org.apache.harmony.dalvik.ddmc.Chunk | captureLayers(android.view.View rootView)Returns a buffer with region details & bitmap of every single view.
ByteArrayOutputStream b = new ByteArrayOutputStream(1024);
DataOutputStream dos = new DataOutputStream(b);
try {
ViewDebug.captureLayers(rootView, dos);
} catch (IOException e) {
return createFailChunk(1, "Unexpected error while obtaining view hierarchy: "
+ e.getMessage());
} finally {
try {
dos.close();
} catch (IOException e) {
// ignore
}
}
byte[] data = b.toByteArray();
return new Chunk(CHUNK_VURT, data, 0, data.length);
| private org.apache.harmony.dalvik.ddmc.Chunk | captureView(android.view.View rootView, android.view.View targetView)
ByteArrayOutputStream b = new ByteArrayOutputStream(1024);
try {
ViewDebug.capture(rootView, b, targetView);
} catch (IOException e) {
return createFailChunk(1, "Unexpected error while capturing view: "
+ e.getMessage());
}
byte[] data = b.toByteArray();
return new Chunk(CHUNK_VUOP, data, 0, data.length);
| public void | connected()
| public void | disconnected()
| private org.apache.harmony.dalvik.ddmc.Chunk | dumpDisplayLists(android.view.View rootView, android.view.View targetView)Returns the display lists corresponding to the provided view.
rootView.post(new Runnable() {
@Override
public void run() {
ViewDebug.outputDisplayList(rootView, targetView);
}
});
return null;
| private org.apache.harmony.dalvik.ddmc.Chunk | dumpHierarchy(android.view.View rootView, java.nio.ByteBuffer in)Returns the view hierarchy and/or view properties starting at the provided view.
Based on the input options, the return data may include:
- just the view hierarchy
- view hierarchy & the properties for each of the views
- just the view properties for a specific view.
TODO: Currently this only returns views starting at the root, need to fix so that
it can return properties of any view.
boolean skipChildren = in.getInt() > 0;
boolean includeProperties = in.getInt() > 0;
ByteArrayOutputStream b = new ByteArrayOutputStream(1024);
try {
ViewDebug.dump(rootView, skipChildren, includeProperties, b);
} catch (IOException e) {
return createFailChunk(1, "Unexpected error while obtaining view hierarchy: "
+ e.getMessage());
}
byte[] data = b.toByteArray();
return new Chunk(CHUNK_VURT, data, 0, data.length);
| private org.apache.harmony.dalvik.ddmc.Chunk | dumpTheme(android.view.View rootView)Returns the Theme dump of the provided view.
ByteArrayOutputStream b = new ByteArrayOutputStream(1024);
try {
ViewDebug.dumpTheme(rootView, b);
} catch (IOException e) {
return createFailChunk(1, "Unexpected error while dumping the theme: "
+ e.getMessage());
}
byte[] data = b.toByteArray();
return new Chunk(CHUNK_VURT, data, 0, data.length);
| private android.view.View | getRootView(java.nio.ByteBuffer in)
try {
int viewRootNameLength = in.getInt();
String viewRootName = getString(in, viewRootNameLength);
return WindowManagerGlobal.getInstance().getRootView(viewRootName);
} catch (BufferUnderflowException e) {
return null;
}
| private android.view.View | getTargetView(android.view.View root, java.nio.ByteBuffer in)
int viewLength;
String viewName;
try {
viewLength = in.getInt();
viewName = getString(in, viewLength);
} catch (BufferUnderflowException e) {
return null;
}
return ViewDebug.findView(root, viewName);
| public org.apache.harmony.dalvik.ddmc.Chunk | handleChunk(org.apache.harmony.dalvik.ddmc.Chunk request)
int type = request.type;
if (type == CHUNK_VUGL) {
return handleOpenGlTrace(request);
} else if (type == CHUNK_VULW) {
return listWindows();
}
ByteBuffer in = wrapChunk(request);
int op = in.getInt();
View rootView = getRootView(in);
if (rootView == null) {
return createFailChunk(ERR_INVALID_PARAM, "Invalid View Root");
}
if (type == CHUNK_VURT) {
if (op == VURT_DUMP_HIERARCHY)
return dumpHierarchy(rootView, in);
else if (op == VURT_CAPTURE_LAYERS)
return captureLayers(rootView);
else if (op == VURT_DUMP_THEME)
return dumpTheme(rootView);
else
return createFailChunk(ERR_INVALID_OP, "Unknown view root operation: " + op);
}
final View targetView = getTargetView(rootView, in);
if (targetView == null) {
return createFailChunk(ERR_INVALID_PARAM, "Invalid target view");
}
if (type == CHUNK_VUOP) {
switch (op) {
case VUOP_CAPTURE_VIEW:
return captureView(rootView, targetView);
case VUOP_DUMP_DISPLAYLIST:
return dumpDisplayLists(rootView, targetView);
case VUOP_PROFILE_VIEW:
return profileView(rootView, targetView);
case VUOP_INVOKE_VIEW_METHOD:
return invokeViewMethod(rootView, targetView, in);
case VUOP_SET_LAYOUT_PARAMETER:
return setLayoutParameter(rootView, targetView, in);
default:
return createFailChunk(ERR_INVALID_OP, "Unknown view operation: " + op);
}
} else {
throw new RuntimeException("Unknown packet " + ChunkHandler.name(type));
}
| private org.apache.harmony.dalvik.ddmc.Chunk | handleOpenGlTrace(org.apache.harmony.dalvik.ddmc.Chunk request)
ByteBuffer in = wrapChunk(request);
GLUtils.setTracingLevel(in.getInt());
return null; // empty response
| private org.apache.harmony.dalvik.ddmc.Chunk | invokeViewMethod(android.view.View rootView, android.view.View targetView, java.nio.ByteBuffer in)Invokes provided method on the view.
The method name and its arguments are passed in as inputs via the byte buffer.
The buffer contains:
- len(method name)
- method name
- # of args
- arguments: Each argument comprises of a type specifier followed by the actual argument.
The type specifier is a single character as used in JNI:
(Z - boolean, B - byte, C - char, S - short, I - int, J - long,
F - float, D - double).
The type specifier is followed by the actual value of argument.
Booleans are encoded via bytes with 0 indicating false.
Methods that take no arguments need only specify the method name.
int l = in.getInt();
String methodName = getString(in, l);
Class<?>[] argTypes;
Object[] args;
if (!in.hasRemaining()) {
argTypes = new Class<?>[0];
args = new Object[0];
} else {
int nArgs = in.getInt();
argTypes = new Class<?>[nArgs];
args = new Object[nArgs];
for (int i = 0; i < nArgs; i++) {
char c = in.getChar();
switch (c) {
case 'Z":
argTypes[i] = boolean.class;
args[i] = in.get() == 0 ? false : true;
break;
case 'B":
argTypes[i] = byte.class;
args[i] = in.get();
break;
case 'C":
argTypes[i] = char.class;
args[i] = in.getChar();
break;
case 'S":
argTypes[i] = short.class;
args[i] = in.getShort();
break;
case 'I":
argTypes[i] = int.class;
args[i] = in.getInt();
break;
case 'J":
argTypes[i] = long.class;
args[i] = in.getLong();
break;
case 'F":
argTypes[i] = float.class;
args[i] = in.getFloat();
break;
case 'D":
argTypes[i] = double.class;
args[i] = in.getDouble();
break;
default:
Log.e(TAG, "arg " + i + ", unrecognized type: " + c);
return createFailChunk(ERR_INVALID_PARAM,
"Unsupported parameter type (" + c + ") to invoke view method.");
}
}
}
Method method = null;
try {
method = targetView.getClass().getMethod(methodName, argTypes);
} catch (NoSuchMethodException e) {
Log.e(TAG, "No such method: " + e.getMessage());
return createFailChunk(ERR_INVALID_PARAM,
"No such method: " + e.getMessage());
}
try {
ViewDebug.invokeViewMethod(targetView, method, args);
} catch (Exception e) {
Log.e(TAG, "Exception while invoking method: " + e.getCause().getMessage());
String msg = e.getCause().getMessage();
if (msg == null) {
msg = e.getCause().toString();
}
return createFailChunk(ERR_EXCEPTION, msg);
}
return null;
| private org.apache.harmony.dalvik.ddmc.Chunk | listWindows()Returns the list of windows owned by this client.
String[] windowNames = WindowManagerGlobal.getInstance().getViewRootNames();
int responseLength = 4; // # of windows
for (String name : windowNames) {
responseLength += 4; // length of next window name
responseLength += name.length() * 2; // window name
}
ByteBuffer out = ByteBuffer.allocate(responseLength);
out.order(ChunkHandler.CHUNK_ORDER);
out.putInt(windowNames.length);
for (String name : windowNames) {
out.putInt(name.length());
putString(out, name);
}
return new Chunk(CHUNK_VULW, out);
| private org.apache.harmony.dalvik.ddmc.Chunk | profileView(android.view.View rootView, android.view.View targetView)Profiles provided view.
ByteArrayOutputStream b = new ByteArrayOutputStream(32 * 1024);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(b), 32 * 1024);
try {
ViewDebug.profileViewAndChildren(targetView, bw);
} catch (IOException e) {
return createFailChunk(1, "Unexpected error while profiling view: " + e.getMessage());
} finally {
try {
bw.close();
} catch (IOException e) {
// ignore
}
}
byte[] data = b.toByteArray();
return new Chunk(CHUNK_VUOP, data, 0, data.length);
| public static void | register()
DdmServer.registerHandler(CHUNK_VUGL, sInstance);
DdmServer.registerHandler(CHUNK_VULW, sInstance);
DdmServer.registerHandler(CHUNK_VURT, sInstance);
DdmServer.registerHandler(CHUNK_VUOP, sInstance);
| private org.apache.harmony.dalvik.ddmc.Chunk | setLayoutParameter(android.view.View rootView, android.view.View targetView, java.nio.ByteBuffer in)
int l = in.getInt();
String param = getString(in, l);
int value = in.getInt();
try {
ViewDebug.setLayoutParameter(targetView, param, value);
} catch (Exception e) {
Log.e(TAG, "Exception setting layout parameter: " + e);
return createFailChunk(ERR_EXCEPTION, "Error accessing field "
+ param + ":" + e.getMessage());
}
return null;
|
|