summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/ViewDebug.java20
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerShellCommand.java56
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) {