diff options
| -rw-r--r-- | core/java/android/view/ViewDebug.java | 20 | ||||
| -rw-r--r-- | services/core/java/com/android/server/wm/WindowManagerShellCommand.java | 56 |
2 files changed, 75 insertions, 1 deletions
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java index 36daa5c57700..a62ba63b64e4 100644 --- a/core/java/android/view/ViewDebug.java +++ b/core/java/android/view/ViewDebug.java @@ -415,6 +415,11 @@ public class ViewDebug { private static final String REMOTE_COMMAND_CAPTURE = "CAPTURE"; private static final String REMOTE_COMMAND_DUMP = "DUMP"; private static final String REMOTE_COMMAND_DUMP_THEME = "DUMP_THEME"; + /** + * Similar to REMOTE_COMMAND_DUMP but uses ViewHierarchyEncoder instead of flat text + * @hide + */ + public static final String REMOTE_COMMAND_DUMP_ENCODED = "DUMP_ENCODED"; private static final String REMOTE_COMMAND_INVALIDATE = "INVALIDATE"; private static final String REMOTE_COMMAND_REQUEST_LAYOUT = "REQUEST_LAYOUT"; private static final String REMOTE_PROFILE = "PROFILE"; @@ -527,7 +532,6 @@ public class ViewDebug { @UnsupportedAppUsage static void dispatchCommand(View view, String command, String parameters, OutputStream clientStream) throws IOException { - // Paranoid but safe... view = view.getRootView(); @@ -535,6 +539,8 @@ public class ViewDebug { dump(view, false, true, clientStream); } else if (REMOTE_COMMAND_DUMP_THEME.equalsIgnoreCase(command)) { dumpTheme(view, clientStream); + } else if (REMOTE_COMMAND_DUMP_ENCODED.equalsIgnoreCase(command)) { + dumpEncoded(view, clientStream); } else if (REMOTE_COMMAND_CAPTURE_LAYERS.equalsIgnoreCase(command)) { captureLayers(view, new DataOutputStream(clientStream)); } else { @@ -1198,6 +1204,18 @@ public class ViewDebug { encoder.endStream(); } + private static void dumpEncoded(@NonNull final View view, @NonNull OutputStream out) + throws IOException { + ByteArrayOutputStream baOut = new ByteArrayOutputStream(); + + final ViewHierarchyEncoder encoder = new ViewHierarchyEncoder(baOut); + encoder.addProperty("window:left", view.mAttachInfo.mWindowLeft); + encoder.addProperty("window:top", view.mAttachInfo.mWindowTop); + view.encode(encoder); + encoder.endStream(); + out.write(baOut.toByteArray()); + } + /** * Dumps the theme attributes from the given View. * @hide diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java index 8e955cf3a8bb..22183667832e 100644 --- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java +++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java @@ -20,19 +20,27 @@ import static android.os.Build.IS_USER; import android.graphics.Point; import android.graphics.Rect; +import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ShellCommand; import android.os.UserHandle; import android.util.DisplayMetrics; +import android.util.Pair; import android.view.Display; import android.view.IWindowManager; import android.view.Surface; +import android.view.ViewDebug; +import com.android.internal.os.ByteTransferPipe; import com.android.server.protolog.ProtoLogImpl; +import java.io.IOException; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; /** * ShellCommands for WindowManagerService. @@ -81,6 +89,8 @@ public class WindowManagerShellCommand extends ShellCommand { return runSetDisplayUserRotation(pw); case "set-fix-to-user-rotation": return runSetFixToUserRotation(pw); + case "dump-visible-window-views": + return runDumpVisibleWindowViews(pw); default: return handleDefaultCommands(cmd); } @@ -341,6 +351,50 @@ public class WindowManagerShellCommand extends ShellCommand { return 0; } + private int runDumpVisibleWindowViews(PrintWriter pw) { + ParcelFileDescriptor outFile = openFileForSystem(getNextArgRequired(), "w"); + try (ZipOutputStream out = new ZipOutputStream( + new ParcelFileDescriptor.AutoCloseOutputStream(outFile))) { + ArrayList<Pair<String, ByteTransferPipe>> requestList = new ArrayList<>(); + synchronized (mInternal.mGlobalLock) { + // Request dump from all windows parallelly before writing to disk. + mInternal.mRoot.forAllWindows(w -> { + if (w.isVisible()) { + ByteTransferPipe pipe = null; + try { + pipe = new ByteTransferPipe(); + w.mClient.executeCommand(ViewDebug.REMOTE_COMMAND_DUMP_ENCODED, null, + pipe.getWriteFd()); + requestList.add(Pair.create(w.getName(), pipe)); + } catch (IOException | RemoteException e) { + // Skip this window + pw.println("Error for window " + w.getName() + " : " + e.getMessage()); + if (pipe != null) { + pipe.kill(); + } + } + } + }, false /* traverseTopToBottom */); + } + for (Pair<String, ByteTransferPipe> entry : requestList) { + byte[] data; + try { + data = entry.second.get(); + } catch (IOException e) { + // Ignore this window + pw.println( + "Error for window " + entry.first + " : " + e.getMessage()); + continue; + } + out.putNextEntry(new ZipEntry(entry.first)); + out.write(data); + } + } catch (IOException e) { + pw.println("Error fetching dump " + e.getMessage()); + } + return 0; + } + @Override public void onHelp() { PrintWriter pw = getOutPrintWriter(); @@ -360,6 +414,8 @@ public class WindowManagerShellCommand extends ShellCommand { pw.println(" Dismiss the keyguard, prompting user for auth if necessary."); pw.println(" set-user-rotation [free|lock] [-d DISPLAY_ID] [rotation]"); pw.println(" Set user rotation mode and user rotation."); + pw.println(" dump-visible-window-views out-file"); + pw.println(" Dumps the encoded view hierarchies of visible windows"); pw.println(" set-fix-to-user-rotation [-d DISPLAY_ID] [enabled|disabled]"); pw.println(" Enable or disable rotating display for app requested orientation."); if (!IS_USER) { |