Loading core/java/android/ddm/DdmHandleGlTracing.javadeleted 100644 → 0 +0 −60 Original line number Diff line number Diff line /* * Copyright (C) 2012 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 android.ddm; import android.opengl.GLUtils; import org.apache.harmony.dalvik.ddmc.Chunk; import org.apache.harmony.dalvik.ddmc.ChunkHandler; import org.apache.harmony.dalvik.ddmc.DdmServer; import java.nio.ByteBuffer; public class DdmHandleGlTracing extends ChunkHandler { /** GL TRace control packets. Packet data controls starting/stopping the trace. */ public static final int CHUNK_GLTR = type("GLTR"); private static final DdmHandleGlTracing sInstance = new DdmHandleGlTracing(); /** singleton, do not instantiate. */ private DdmHandleGlTracing() {} public static void register() { DdmServer.registerHandler(CHUNK_GLTR, sInstance); } @Override public void connected() { } @Override public void disconnected() { } @Override public Chunk handleChunk(Chunk request) { int type = request.type; if (type != CHUNK_GLTR) { throw new RuntimeException("Unknown packet " + ChunkHandler.name(type)); } ByteBuffer in = wrapChunk(request); GLUtils.setTracingLevel(in.getInt()); return null; // empty response } } core/java/android/ddm/DdmHandleHello.java +11 −8 Original line number Diff line number Diff line Loading @@ -36,7 +36,10 @@ public class DdmHandleHello extends ChunkHandler { private static DdmHandleHello mInstance = new DdmHandleHello(); private static final String[] NATIVE_FEATURES = new String[] { "opengl-tracing" }; private static final String[] FRAMEWORK_FEATURES = new String[] { "opengl-tracing", "view-hierarchy", }; /* singleton, do not instantiate */ private DdmHandleHello() {} Loading Loading @@ -155,22 +158,22 @@ public class DdmHandleHello extends ChunkHandler { if (false) Log.v("ddm-heap", "Got feature list request"); int size = 4 + 4 * (vmFeatures.length + NATIVE_FEATURES.length); int size = 4 + 4 * (vmFeatures.length + FRAMEWORK_FEATURES.length); for (int i = vmFeatures.length-1; i >= 0; i--) size += vmFeatures[i].length() * 2; for (int i = NATIVE_FEATURES.length-1; i>= 0; i--) size += NATIVE_FEATURES[i].length() * 2; for (int i = FRAMEWORK_FEATURES.length-1; i>= 0; i--) size += FRAMEWORK_FEATURES[i].length() * 2; ByteBuffer out = ByteBuffer.allocate(size); out.order(ChunkHandler.CHUNK_ORDER); out.putInt(vmFeatures.length + NATIVE_FEATURES.length); out.putInt(vmFeatures.length + FRAMEWORK_FEATURES.length); for (int i = vmFeatures.length-1; i >= 0; i--) { out.putInt(vmFeatures[i].length()); putString(out, vmFeatures[i]); } for (int i = NATIVE_FEATURES.length-1; i >= 0; i--) { out.putInt(NATIVE_FEATURES[i].length()); putString(out, NATIVE_FEATURES[i]); for (int i = FRAMEWORK_FEATURES.length-1; i >= 0; i--) { out.putInt(FRAMEWORK_FEATURES[i].length()); putString(out, FRAMEWORK_FEATURES[i]); } return new Chunk(CHUNK_FEAT, out); Loading core/java/android/ddm/DdmHandleViewDebug.java 0 → 100644 +315 −0 Original line number Diff line number Diff line /* * Copyright (C) 2013 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 android.ddm; import android.opengl.GLUtils; import android.util.Log; import android.view.View; import android.view.ViewDebug; import android.view.ViewRootImpl; import android.view.WindowManagerGlobal; import org.apache.harmony.dalvik.ddmc.Chunk; import org.apache.harmony.dalvik.ddmc.ChunkHandler; import org.apache.harmony.dalvik.ddmc.DdmServer; import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; /** * Handle various requests related to profiling / debugging of the view system. * Support for these features are advertised via {@link DdmHandleHello}. */ public class DdmHandleViewDebug extends ChunkHandler { /** Enable/Disable tracing of OpenGL calls. */ public static final int CHUNK_VUGL = type("VUGL"); /** List {@link ViewRootImpl}'s of this process. */ private static final int CHUNK_VULW = type("VULW"); /** Operation on view root, first parameter in packet should be one of VURT_* constants */ private static final int CHUNK_VURT = type("VURT"); /** Dump view hierarchy. */ private static final int VURT_DUMP_HIERARCHY = 1; /** Capture View Layers. */ private static final int VURT_CAPTURE_LAYERS = 2; /** * Generic View Operation, first parameter in the packet should be one of the * VUOP_* constants below. */ private static final int CHUNK_VUOP = type("VUOP"); /** Capture View. */ private static final int VUOP_CAPTURE_VIEW = 1; /** Obtain the Display List corresponding to the view. */ private static final int VUOP_DUMP_DISPLAYLIST = 2; /** Invalidate View. */ private static final int VUOP_INVALIDATE_VIEW = 3; /** Re-layout given view. */ private static final int VUOP_LAYOUT_VIEW = 4; /** Profile a view. */ private static final int VUOP_PROFILE_VIEW = 5; /** Error code indicating operation specified in chunk is invalid. */ private static final int ERR_INVALID_OP = -1; /** Error code indicating that the parameters are invalid. */ private static final int ERR_INVALID_PARAM = -2; private static final DdmHandleViewDebug sInstance = new DdmHandleViewDebug(); /** singleton, do not instantiate. */ private DdmHandleViewDebug() {} public static void register() { DdmServer.registerHandler(CHUNK_VUGL, sInstance); DdmServer.registerHandler(CHUNK_VULW, sInstance); DdmServer.registerHandler(CHUNK_VURT, sInstance); DdmServer.registerHandler(CHUNK_VUOP, sInstance); } @Override public void connected() { } @Override public void disconnected() { } @Override public Chunk handleChunk(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 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_INVALIDATE_VIEW: return invalidateView(rootView, targetView); case VUOP_LAYOUT_VIEW: return layoutView(rootView, targetView); case VUOP_PROFILE_VIEW: return profileView(rootView, targetView); default: return createFailChunk(ERR_INVALID_OP, "Unknown view operation: " + op); } } else { throw new RuntimeException("Unknown packet " + ChunkHandler.name(type)); } } private Chunk handleOpenGlTrace(Chunk request) { ByteBuffer in = wrapChunk(request); GLUtils.setTracingLevel(in.getInt()); return null; // empty response } /** Returns the list of windows owned by this client. */ private Chunk listWindows() { 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 View getRootView(ByteBuffer in) { try { int viewRootNameLength = in.getInt(); String viewRootName = getString(in, viewRootNameLength); return WindowManagerGlobal.getInstance().getRootView(viewRootName); } catch (BufferUnderflowException e) { return null; } } private View getTargetView(View root, ByteBuffer in) { int viewLength; String viewName; try { viewLength = in.getInt(); viewName = getString(in, viewLength); } catch (BufferUnderflowException e) { return null; } return ViewDebug.findView(root, viewName); } /** * 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. */ private Chunk dumpHierarchy(View rootView, ByteBuffer in) { 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); } /** Returns a buffer with region details & bitmap of every single view. */ private Chunk captureLayers(View rootView) { 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 Chunk captureView(View rootView, 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); } /** Returns the display lists corresponding to the provided view. */ private Chunk dumpDisplayLists(final View rootView, final View targetView) { rootView.post(new Runnable() { @Override public void run() { ViewDebug.outputDisplayList(rootView, targetView); } }); return null; } /** Invalidates provided view. */ private Chunk invalidateView(final View rootView, final View targetView) { targetView.postInvalidate(); return null; } /** Lays out provided view. */ private Chunk layoutView(View rootView, final View targetView) { rootView.post(new Runnable() { @Override public void run() { targetView.requestLayout(); } }); return null; } /** Profiles provided view. */ private Chunk profileView(View rootView, final View targetView) { 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); } } core/java/android/ddm/DdmRegister.java +1 −1 Original line number Diff line number Diff line Loading @@ -51,7 +51,7 @@ public class DdmRegister { DdmHandleNativeHeap.register(); DdmHandleProfiling.register(); DdmHandleExit.register(); DdmHandleGlTracing.register(); DdmHandleViewDebug.register(); DdmServer.registrationComplete(); } Loading core/java/android/view/ViewDebug.java +41 −14 Original line number Diff line number Diff line Loading @@ -406,7 +406,7 @@ public class ViewDebug { view = view.getRootView(); if (REMOTE_COMMAND_DUMP.equalsIgnoreCase(command)) { dump(view, clientStream); dump(view, false, true, clientStream); } else if (REMOTE_COMMAND_CAPTURE_LAYERS.equalsIgnoreCase(command)) { captureLayers(view, new DataOutputStream(clientStream)); } else { Loading @@ -425,7 +425,8 @@ public class ViewDebug { } } private static View findView(View root, String parameter) { /** @hide */ public static View findView(View root, String parameter) { // Look by type/hashcode if (parameter.indexOf('@') != -1) { final String[] ids = parameter.split("@"); Loading Loading @@ -488,7 +489,8 @@ public class ViewDebug { } } private static void profileViewAndChildren(final View view, BufferedWriter out) /** @hide */ public static void profileViewAndChildren(final View view, BufferedWriter out) throws IOException { profileViewAndChildren(view, out, true); } Loading Loading @@ -623,7 +625,8 @@ public class ViewDebug { return duration[0]; } private static void captureLayers(View root, final DataOutputStream clientStream) /** @hide */ public static void captureLayers(View root, final DataOutputStream clientStream) throws IOException { try { Loading Loading @@ -695,10 +698,21 @@ public class ViewDebug { view.getViewRootImpl().outputDisplayList(view); } /** @hide */ public static void outputDisplayList(View root, View target) { root.getViewRootImpl().outputDisplayList(target); } private static void capture(View root, final OutputStream clientStream, String parameter) throws IOException { final View captureView = findView(root, parameter); capture(root, clientStream, captureView); } /** @hide */ public static void capture(View root, final OutputStream clientStream, View captureView) throws IOException { Bitmap b = performViewCapture(captureView, false); if (b == null) { Loading Loading @@ -752,14 +766,20 @@ public class ViewDebug { return null; } private static void dump(View root, OutputStream clientStream) throws IOException { /** * Dumps the view hierarchy starting from the given view. * @hide */ public static void dump(View root, boolean skipChildren, boolean includeProperties, OutputStream clientStream) throws IOException { BufferedWriter out = null; try { out = new BufferedWriter(new OutputStreamWriter(clientStream, "utf-8"), 32 * 1024); View view = root.getRootView(); if (view instanceof ViewGroup) { ViewGroup group = (ViewGroup) view; dumpViewHierarchyWithProperties(group.getContext(), group, out, 0); dumpViewHierarchy(group.getContext(), group, out, 0, skipChildren, includeProperties); } out.write("DONE."); out.newLine(); Loading Loading @@ -804,9 +824,13 @@ public class ViewDebug { return view.getClass().getName().equals(className) && view.hashCode() == hashCode; } private static void dumpViewHierarchyWithProperties(Context context, ViewGroup group, BufferedWriter out, int level) { if (!dumpViewWithProperties(context, group, out, level)) { private static void dumpViewHierarchy(Context context, ViewGroup group, BufferedWriter out, int level, boolean skipChildren, boolean includeProperties) { if (!dumpView(context, group, out, level, includeProperties)) { return; } if (skipChildren) { return; } Loading @@ -814,9 +838,10 @@ public class ViewDebug { for (int i = 0; i < count; i++) { final View view = group.getChildAt(i); if (view instanceof ViewGroup) { dumpViewHierarchyWithProperties(context, (ViewGroup) view, out, level + 1); dumpViewHierarchy(context, (ViewGroup) view, out, level + 1, skipChildren, includeProperties); } else { dumpViewWithProperties(context, view, out, level + 1); dumpView(context, view, out, level + 1, includeProperties); } } if (group instanceof HierarchyHandler) { Loading @@ -824,8 +849,8 @@ public class ViewDebug { } } private static boolean dumpViewWithProperties(Context context, View view, BufferedWriter out, int level) { private static boolean dumpView(Context context, View view, BufferedWriter out, int level, boolean includeProperties) { try { for (int i = 0; i < level; i++) { Loading @@ -835,7 +860,9 @@ public class ViewDebug { out.write('@'); out.write(Integer.toHexString(view.hashCode())); out.write(' '); if (includeProperties) { dumpViewProperties(context, view, out); } out.newLine(); } catch (IOException e) { Log.w("View", "Error while dumping hierarchy tree"); Loading Loading
core/java/android/ddm/DdmHandleGlTracing.javadeleted 100644 → 0 +0 −60 Original line number Diff line number Diff line /* * Copyright (C) 2012 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 android.ddm; import android.opengl.GLUtils; import org.apache.harmony.dalvik.ddmc.Chunk; import org.apache.harmony.dalvik.ddmc.ChunkHandler; import org.apache.harmony.dalvik.ddmc.DdmServer; import java.nio.ByteBuffer; public class DdmHandleGlTracing extends ChunkHandler { /** GL TRace control packets. Packet data controls starting/stopping the trace. */ public static final int CHUNK_GLTR = type("GLTR"); private static final DdmHandleGlTracing sInstance = new DdmHandleGlTracing(); /** singleton, do not instantiate. */ private DdmHandleGlTracing() {} public static void register() { DdmServer.registerHandler(CHUNK_GLTR, sInstance); } @Override public void connected() { } @Override public void disconnected() { } @Override public Chunk handleChunk(Chunk request) { int type = request.type; if (type != CHUNK_GLTR) { throw new RuntimeException("Unknown packet " + ChunkHandler.name(type)); } ByteBuffer in = wrapChunk(request); GLUtils.setTracingLevel(in.getInt()); return null; // empty response } }
core/java/android/ddm/DdmHandleHello.java +11 −8 Original line number Diff line number Diff line Loading @@ -36,7 +36,10 @@ public class DdmHandleHello extends ChunkHandler { private static DdmHandleHello mInstance = new DdmHandleHello(); private static final String[] NATIVE_FEATURES = new String[] { "opengl-tracing" }; private static final String[] FRAMEWORK_FEATURES = new String[] { "opengl-tracing", "view-hierarchy", }; /* singleton, do not instantiate */ private DdmHandleHello() {} Loading Loading @@ -155,22 +158,22 @@ public class DdmHandleHello extends ChunkHandler { if (false) Log.v("ddm-heap", "Got feature list request"); int size = 4 + 4 * (vmFeatures.length + NATIVE_FEATURES.length); int size = 4 + 4 * (vmFeatures.length + FRAMEWORK_FEATURES.length); for (int i = vmFeatures.length-1; i >= 0; i--) size += vmFeatures[i].length() * 2; for (int i = NATIVE_FEATURES.length-1; i>= 0; i--) size += NATIVE_FEATURES[i].length() * 2; for (int i = FRAMEWORK_FEATURES.length-1; i>= 0; i--) size += FRAMEWORK_FEATURES[i].length() * 2; ByteBuffer out = ByteBuffer.allocate(size); out.order(ChunkHandler.CHUNK_ORDER); out.putInt(vmFeatures.length + NATIVE_FEATURES.length); out.putInt(vmFeatures.length + FRAMEWORK_FEATURES.length); for (int i = vmFeatures.length-1; i >= 0; i--) { out.putInt(vmFeatures[i].length()); putString(out, vmFeatures[i]); } for (int i = NATIVE_FEATURES.length-1; i >= 0; i--) { out.putInt(NATIVE_FEATURES[i].length()); putString(out, NATIVE_FEATURES[i]); for (int i = FRAMEWORK_FEATURES.length-1; i >= 0; i--) { out.putInt(FRAMEWORK_FEATURES[i].length()); putString(out, FRAMEWORK_FEATURES[i]); } return new Chunk(CHUNK_FEAT, out); Loading
core/java/android/ddm/DdmHandleViewDebug.java 0 → 100644 +315 −0 Original line number Diff line number Diff line /* * Copyright (C) 2013 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 android.ddm; import android.opengl.GLUtils; import android.util.Log; import android.view.View; import android.view.ViewDebug; import android.view.ViewRootImpl; import android.view.WindowManagerGlobal; import org.apache.harmony.dalvik.ddmc.Chunk; import org.apache.harmony.dalvik.ddmc.ChunkHandler; import org.apache.harmony.dalvik.ddmc.DdmServer; import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; /** * Handle various requests related to profiling / debugging of the view system. * Support for these features are advertised via {@link DdmHandleHello}. */ public class DdmHandleViewDebug extends ChunkHandler { /** Enable/Disable tracing of OpenGL calls. */ public static final int CHUNK_VUGL = type("VUGL"); /** List {@link ViewRootImpl}'s of this process. */ private static final int CHUNK_VULW = type("VULW"); /** Operation on view root, first parameter in packet should be one of VURT_* constants */ private static final int CHUNK_VURT = type("VURT"); /** Dump view hierarchy. */ private static final int VURT_DUMP_HIERARCHY = 1; /** Capture View Layers. */ private static final int VURT_CAPTURE_LAYERS = 2; /** * Generic View Operation, first parameter in the packet should be one of the * VUOP_* constants below. */ private static final int CHUNK_VUOP = type("VUOP"); /** Capture View. */ private static final int VUOP_CAPTURE_VIEW = 1; /** Obtain the Display List corresponding to the view. */ private static final int VUOP_DUMP_DISPLAYLIST = 2; /** Invalidate View. */ private static final int VUOP_INVALIDATE_VIEW = 3; /** Re-layout given view. */ private static final int VUOP_LAYOUT_VIEW = 4; /** Profile a view. */ private static final int VUOP_PROFILE_VIEW = 5; /** Error code indicating operation specified in chunk is invalid. */ private static final int ERR_INVALID_OP = -1; /** Error code indicating that the parameters are invalid. */ private static final int ERR_INVALID_PARAM = -2; private static final DdmHandleViewDebug sInstance = new DdmHandleViewDebug(); /** singleton, do not instantiate. */ private DdmHandleViewDebug() {} public static void register() { DdmServer.registerHandler(CHUNK_VUGL, sInstance); DdmServer.registerHandler(CHUNK_VULW, sInstance); DdmServer.registerHandler(CHUNK_VURT, sInstance); DdmServer.registerHandler(CHUNK_VUOP, sInstance); } @Override public void connected() { } @Override public void disconnected() { } @Override public Chunk handleChunk(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 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_INVALIDATE_VIEW: return invalidateView(rootView, targetView); case VUOP_LAYOUT_VIEW: return layoutView(rootView, targetView); case VUOP_PROFILE_VIEW: return profileView(rootView, targetView); default: return createFailChunk(ERR_INVALID_OP, "Unknown view operation: " + op); } } else { throw new RuntimeException("Unknown packet " + ChunkHandler.name(type)); } } private Chunk handleOpenGlTrace(Chunk request) { ByteBuffer in = wrapChunk(request); GLUtils.setTracingLevel(in.getInt()); return null; // empty response } /** Returns the list of windows owned by this client. */ private Chunk listWindows() { 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 View getRootView(ByteBuffer in) { try { int viewRootNameLength = in.getInt(); String viewRootName = getString(in, viewRootNameLength); return WindowManagerGlobal.getInstance().getRootView(viewRootName); } catch (BufferUnderflowException e) { return null; } } private View getTargetView(View root, ByteBuffer in) { int viewLength; String viewName; try { viewLength = in.getInt(); viewName = getString(in, viewLength); } catch (BufferUnderflowException e) { return null; } return ViewDebug.findView(root, viewName); } /** * 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. */ private Chunk dumpHierarchy(View rootView, ByteBuffer in) { 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); } /** Returns a buffer with region details & bitmap of every single view. */ private Chunk captureLayers(View rootView) { 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 Chunk captureView(View rootView, 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); } /** Returns the display lists corresponding to the provided view. */ private Chunk dumpDisplayLists(final View rootView, final View targetView) { rootView.post(new Runnable() { @Override public void run() { ViewDebug.outputDisplayList(rootView, targetView); } }); return null; } /** Invalidates provided view. */ private Chunk invalidateView(final View rootView, final View targetView) { targetView.postInvalidate(); return null; } /** Lays out provided view. */ private Chunk layoutView(View rootView, final View targetView) { rootView.post(new Runnable() { @Override public void run() { targetView.requestLayout(); } }); return null; } /** Profiles provided view. */ private Chunk profileView(View rootView, final View targetView) { 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); } }
core/java/android/ddm/DdmRegister.java +1 −1 Original line number Diff line number Diff line Loading @@ -51,7 +51,7 @@ public class DdmRegister { DdmHandleNativeHeap.register(); DdmHandleProfiling.register(); DdmHandleExit.register(); DdmHandleGlTracing.register(); DdmHandleViewDebug.register(); DdmServer.registrationComplete(); } Loading
core/java/android/view/ViewDebug.java +41 −14 Original line number Diff line number Diff line Loading @@ -406,7 +406,7 @@ public class ViewDebug { view = view.getRootView(); if (REMOTE_COMMAND_DUMP.equalsIgnoreCase(command)) { dump(view, clientStream); dump(view, false, true, clientStream); } else if (REMOTE_COMMAND_CAPTURE_LAYERS.equalsIgnoreCase(command)) { captureLayers(view, new DataOutputStream(clientStream)); } else { Loading @@ -425,7 +425,8 @@ public class ViewDebug { } } private static View findView(View root, String parameter) { /** @hide */ public static View findView(View root, String parameter) { // Look by type/hashcode if (parameter.indexOf('@') != -1) { final String[] ids = parameter.split("@"); Loading Loading @@ -488,7 +489,8 @@ public class ViewDebug { } } private static void profileViewAndChildren(final View view, BufferedWriter out) /** @hide */ public static void profileViewAndChildren(final View view, BufferedWriter out) throws IOException { profileViewAndChildren(view, out, true); } Loading Loading @@ -623,7 +625,8 @@ public class ViewDebug { return duration[0]; } private static void captureLayers(View root, final DataOutputStream clientStream) /** @hide */ public static void captureLayers(View root, final DataOutputStream clientStream) throws IOException { try { Loading Loading @@ -695,10 +698,21 @@ public class ViewDebug { view.getViewRootImpl().outputDisplayList(view); } /** @hide */ public static void outputDisplayList(View root, View target) { root.getViewRootImpl().outputDisplayList(target); } private static void capture(View root, final OutputStream clientStream, String parameter) throws IOException { final View captureView = findView(root, parameter); capture(root, clientStream, captureView); } /** @hide */ public static void capture(View root, final OutputStream clientStream, View captureView) throws IOException { Bitmap b = performViewCapture(captureView, false); if (b == null) { Loading Loading @@ -752,14 +766,20 @@ public class ViewDebug { return null; } private static void dump(View root, OutputStream clientStream) throws IOException { /** * Dumps the view hierarchy starting from the given view. * @hide */ public static void dump(View root, boolean skipChildren, boolean includeProperties, OutputStream clientStream) throws IOException { BufferedWriter out = null; try { out = new BufferedWriter(new OutputStreamWriter(clientStream, "utf-8"), 32 * 1024); View view = root.getRootView(); if (view instanceof ViewGroup) { ViewGroup group = (ViewGroup) view; dumpViewHierarchyWithProperties(group.getContext(), group, out, 0); dumpViewHierarchy(group.getContext(), group, out, 0, skipChildren, includeProperties); } out.write("DONE."); out.newLine(); Loading Loading @@ -804,9 +824,13 @@ public class ViewDebug { return view.getClass().getName().equals(className) && view.hashCode() == hashCode; } private static void dumpViewHierarchyWithProperties(Context context, ViewGroup group, BufferedWriter out, int level) { if (!dumpViewWithProperties(context, group, out, level)) { private static void dumpViewHierarchy(Context context, ViewGroup group, BufferedWriter out, int level, boolean skipChildren, boolean includeProperties) { if (!dumpView(context, group, out, level, includeProperties)) { return; } if (skipChildren) { return; } Loading @@ -814,9 +838,10 @@ public class ViewDebug { for (int i = 0; i < count; i++) { final View view = group.getChildAt(i); if (view instanceof ViewGroup) { dumpViewHierarchyWithProperties(context, (ViewGroup) view, out, level + 1); dumpViewHierarchy(context, (ViewGroup) view, out, level + 1, skipChildren, includeProperties); } else { dumpViewWithProperties(context, view, out, level + 1); dumpView(context, view, out, level + 1, includeProperties); } } if (group instanceof HierarchyHandler) { Loading @@ -824,8 +849,8 @@ public class ViewDebug { } } private static boolean dumpViewWithProperties(Context context, View view, BufferedWriter out, int level) { private static boolean dumpView(Context context, View view, BufferedWriter out, int level, boolean includeProperties) { try { for (int i = 0; i < level; i++) { Loading @@ -835,7 +860,9 @@ public class ViewDebug { out.write('@'); out.write(Integer.toHexString(view.hashCode())); out.write(' '); if (includeProperties) { dumpViewProperties(context, view, out); } out.newLine(); } catch (IOException e) { Log.w("View", "Error while dumping hierarchy tree"); Loading