diff options
author | Robert Carr <racarr@google.com> | 2016-08-16 16:02:21 -0700 |
---|---|---|
committer | Robert Carr <racarr@google.com> | 2016-09-19 11:19:31 -0700 |
commit | 3b716249cc2f94aa9842576b618998c28593be90 (patch) | |
tree | d4621c132d21655fe67852975c63d858d5998c59 | |
parent | fcdcf7f636ada244a635328e25fdc03959468c8e (diff) |
WindowManager RemoteSurfaceTrace infrastructure
Add "wm surface-trace" command which enables tracing of surface
commands to be switched on at runtime. Primarily intended for use
by WM CTS tests. First target in CTS will be to use show/hide
events to eliminate polling in WM tests and increase speed. Next up
looking at things like verifying various transitions and relaunch
scenarios are flicker free. Later we may want to look at a smarter
or more structured format...but it's really not much hassle to parse
the commands off a pipe so I wanted to get us started.
Test: cts-tradefed run singleCommand cts -o --module CtsWindowManagerHostTestCases --test android.server.cts.SurfaceViewMovementTests#testSurfaceMovesWithParent
Change-Id: I1ff912c405a6cb9996ee9b6e2c465d57706191ba
9 files changed, 329 insertions, 1 deletions
diff --git a/cmds/wm/src/com/android/commands/wm/Wm.java b/cmds/wm/src/com/android/commands/wm/Wm.java index 383cd01ddcd6..b46cd6767a73 100644 --- a/cmds/wm/src/com/android/commands/wm/Wm.java +++ b/cmds/wm/src/com/android/commands/wm/Wm.java @@ -21,16 +21,22 @@ package com.android.commands.wm; import android.content.Context; import android.graphics.Point; import android.graphics.Rect; +import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.util.AndroidException; import android.util.DisplayMetrics; +import android.system.Os; import android.view.Display; import android.view.IWindowManager; import com.android.internal.os.BaseCommand; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.DataInputStream; import java.io.PrintStream; +import java.lang.Runtime; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -69,7 +75,9 @@ public class Wm extends BaseCommand { "wm screen-capture: enable/disable screen capture.\n" + "\n" + "wm dismiss-keyguard: dismiss the keyguard, prompting the user for auth if " + - "necessary.\n" + "necessary.\n" + + "\n" + + "wm surface-trace: log surface commands to stdout.\n" ); } @@ -96,12 +104,60 @@ public class Wm extends BaseCommand { runSetScreenCapture(); } else if (op.equals("dismiss-keyguard")) { runDismissKeyguard(); + } else if (op.equals("surface-trace")) { + runSurfaceTrace(); } else { showError("Error: unknown command '" + op + "'"); return; } } + private void parseTrace(String next, DataInputStream is) throws Exception { + switch (next) { + case "Alpha": + System.out.println(is.readFloat()); + break; + case "Layer": + System.out.println(is.readInt()); + break; + case "Position": + System.out.println(is.readFloat() + ", " + is.readFloat()); + break; + case "Size": + System.out.println(is.readInt() + ", " + is.readInt()); + break; + case "LayerStack": + System.out.println(is.readInt()); + break; + case "Matrix": + System.out.println(is.readFloat() + "," + is.readFloat() + "," + is.readFloat() + "," + + is.readFloat()); + break; + case "Hide": + case "Show": + case "GeometryAppliesWithResize": + break; + } + } + + private void runSurfaceTrace() throws Exception { + ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe(); + + mWm.enableSurfaceTrace(fds[1]); + DataInputStream is = new DataInputStream(new FileInputStream(fds[0].getFileDescriptor())); + + try { + while (true) { + String cmd = is.readUTF(); + String window = is.readUTF(); + System.out.print(cmd + "(" + window + "): "); + parseTrace(cmd, is); + } + } finally { + mWm.disableSurfaceTrace(); + } + } + private void runSetScreenCapture() throws Exception { String userIdStr = nextArg(); String enableStr = nextArg(); diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 1d9f99fa7b12..c16339380294 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -29,6 +29,7 @@ import android.graphics.Point; import android.graphics.Rect; import android.os.Bundle; import android.os.IRemoteCallback; +import android.os.ParcelFileDescriptor; import android.view.IApplicationToken; import android.view.IAppTransitionAnimationSpecsFuture; import android.view.IDockedStackListener; @@ -256,6 +257,13 @@ interface IWindowManager void setScreenCaptureDisabled(int userId, boolean disabled); /** + * Testing and debugging infrastructure for writing surface events + * to given FD. See RemoteSurfaceTrace.java or Wm.java for format. + */ + void enableSurfaceTrace(in ParcelFileDescriptor fd); + void disableSurfaceTrace(); + + /** * Cancels the window transitions for the given task. */ void cancelTaskWindowTransition(int taskId); diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index e778a7f16f25..64568260c022 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -308,6 +308,17 @@ public class SurfaceControl { mCloseGuard.open("release"); } + // This is a transfer constructor, useful for transferring a live SurfaceControl native + // object to another Java wrapper which could have some different behavior, e.g. + // event logging. + public SurfaceControl(SurfaceControl other) { + mName = other.mName; + mNativeObject = other.mNativeObject; + other.mCloseGuard.close(); + other.mNativeObject = 0; + mCloseGuard.open("release"); + } + @Override protected void finalize() throws Throwable { try { diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index ee73deee5a38..6e1cb378b4b1 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -55,6 +55,7 @@ import android.view.Surface; import android.view.animation.Animation; import com.android.internal.util.FastPrintWriter; +import java.io.FileDescriptor; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; @@ -1179,4 +1180,18 @@ class DisplayContent { taskForResize = null; } } + + void enableSurfaceTrace(FileDescriptor fd) { + for (int i = mWindows.size() - 1; i >= 0; i--) { + final WindowState win = mWindows.get(i); + win.mWinAnimator.enableSurfaceTrace(fd); + } + } + + void disableSurfaceTrace() { + for (int i = mWindows.size() - 1; i >= 0; i--) { + final WindowState win = mWindows.get(i); + win.mWinAnimator.disableSurfaceTrace(); + } + } } diff --git a/services/core/java/com/android/server/wm/RemoteSurfaceTrace.java b/services/core/java/com/android/server/wm/RemoteSurfaceTrace.java new file mode 100644 index 000000000000..53bb5e60808b --- /dev/null +++ b/services/core/java/com/android/server/wm/RemoteSurfaceTrace.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2016 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.server.wm; + +import android.graphics.Rect; +import android.graphics.Region; +import android.os.IBinder; +import android.os.Parcel; +import android.util.Slog; +import android.view.SurfaceControl; + +import java.io.FileDescriptor; +import java.io.FileOutputStream; +import java.io.DataOutputStream; + +// A surface control subclass which logs events to a FD in binary format. +// This can be used in our CTS tests to enable a pattern similar to mocking +// the surface control. +// +// See cts/hostsidetests/../../SurfaceTraceReceiver.java for parsing side. +class RemoteSurfaceTrace extends SurfaceControl { + static final String TAG = "RemoteSurfaceTrace"; + + final FileDescriptor mWriteFd; + final DataOutputStream mOut; + + final WindowManagerService mService; + final WindowState mWindow; + + RemoteSurfaceTrace(FileDescriptor fd, SurfaceControl wrapped, WindowState window) { + super(wrapped); + + mWriteFd = fd; + mOut = new DataOutputStream(new FileOutputStream(fd, false)); + + mWindow = window; + mService = mWindow.mService; + } + + @Override + public void setAlpha(float alpha) { + writeFloatEvent("Alpha", alpha); + super.setAlpha(alpha); + } + + @Override + public void setLayer(int zorder) { + writeIntEvent("Layer", zorder); + super.setLayer(zorder); + } + + @Override + public void setPosition(float x, float y) { + writeFloatEvent("Position", x, y); + super.setPosition(x, y); + } + + @Override + public void setGeometryAppliesWithResize() { + writeEvent("GeometryAppliesWithResize"); + super.setGeometryAppliesWithResize(); + } + + @Override + public void setSize(int w, int h) { + writeIntEvent("Size", w, h); + super.setSize(w, h); + } + + @Override + public void setWindowCrop(Rect crop) { + writeRectEvent("WindowCrop", crop); + super.setWindowCrop(crop); + } + + @Override + public void setFinalCrop(Rect crop) { + writeRectEvent("FinalCrop", crop); + super.setFinalCrop(crop); + } + + @Override + public void setLayerStack(int layerStack) { + writeIntEvent("LayerStack", layerStack); + super.setLayerStack(layerStack); + } + + @Override + public void setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) { + writeFloatEvent("Matrix", dsdx, dtdx, dsdy, dtdy); + super.setMatrix(dsdx, dtdx, dsdy, dtdy); + } + + @Override + public void hide() { + writeEvent("hide"); + super.hide(); + } + + @Override + public void show() { + writeEvent("show"); + super.show(); + } + + private void writeEvent(String tag) { + try { + mOut.writeUTF(tag); + mOut.writeUTF(mWindow.getWindowTag().toString()); + } catch (Exception e) { + mService.disableSurfaceTrace(); + } + } + + private void writeIntEvent(String tag, int... values) { + try { + mOut.writeUTF(tag); + mOut.writeUTF(mWindow.getWindowTag().toString()); + for (int value: values) { + mOut.writeInt(value); + } + } catch (Exception e) { + mService.disableSurfaceTrace(); + } + } + + private void writeFloatEvent(String tag, float... values) { + try { + mOut.writeUTF(tag); + mOut.writeUTF(mWindow.getWindowTag().toString()); + for (float value: values) { + mOut.writeFloat(value); + } + } catch (Exception e) { + mService.disableSurfaceTrace(); + } + } + + private void writeRectEvent(String tag, Rect value) { + writeFloatEvent(tag, value.top, value.left, value.right, value.bottom); + } +} diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index a0b74f807910..5180e99b1d88 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -893,6 +893,12 @@ public class WindowManagerService extends IWindowManager.Stub // current configuration. private final DisplayContentList mReconfigureOnConfigurationChanged = new DisplayContentList(); + // State for the RemoteSurfaceTrace system used in testing. If this is enabled SurfaceControl + // instances will be replaced with an instance that writes a binary representation of all + // commands to mSurfaceTraceFd. + boolean mSurfaceTraceEnabled; + ParcelFileDescriptor mSurfaceTraceFd; + /** Listener to notify activity manager about app transitions. */ final WindowManagerInternal.AppTransitionListener mActivityManagerAppTransitionNotifier = new WindowManagerInternal.AppTransitionListener() { @@ -1935,6 +1941,42 @@ public class WindowManagerService extends IWindowManager.Stub return false; } + @Override + public void enableSurfaceTrace(ParcelFileDescriptor pfd) { + int callingUid = Binder.getCallingUid(); + if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID) { + throw new SecurityException("Only shell can call enableSurfaceTrace"); + } + final FileDescriptor fd = pfd.getFileDescriptor(); + + synchronized (mWindowMap) { + if (mSurfaceTraceEnabled) { + disableSurfaceTrace(); + } + mSurfaceTraceEnabled = true; + mSurfaceTraceFd = pfd; + for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) { + DisplayContent dc = mDisplayContents.valueAt(displayNdx); + dc.enableSurfaceTrace(fd); + } + } + } + + @Override + public void disableSurfaceTrace() { + int callingUid = Binder.getCallingUid(); + if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID && + callingUid != Process.SYSTEM_UID) { + throw new SecurityException("Only shell can call disableSurfaceTrace"); + } + mSurfaceTraceEnabled = false; + mSurfaceTraceFd = null; + for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) { + DisplayContent dc = mDisplayContents.valueAt(displayNdx); + dc.disableSurfaceTrace(); + } + } + /** * Set mScreenCaptureDisabled for specific user */ diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 788f28dadfeb..4f6cf2ff85cb 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -70,6 +70,7 @@ import android.view.animation.Transformation; import com.android.server.wm.WindowManagerService.H; import java.io.PrintWriter; +import java.io.FileDescriptor; /** * Keep track of animations and surface operations for a single WindowState. @@ -2006,4 +2007,20 @@ class WindowStateAnimator { DtDy * w.mVScale, false); } } + + void enableSurfaceTrace(FileDescriptor fd) { + if (mSurfaceController != null) { + mSurfaceController.installRemoteTrace(fd); + } + } + + void disableSurfaceTrace() { + if (mSurfaceController != null) { + try { + mSurfaceController.removeRemoteTrace(); + } catch (ClassCastException e) { + Slog.e(TAG, "Disable surface trace for " + this + " but its not enabled"); + } + } + } } diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java index f5ed9d1b8650..60bdf2aae068 100644 --- a/services/core/java/com/android/server/wm/WindowSurfaceController.java +++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java @@ -41,6 +41,7 @@ import android.view.Surface.OutOfResourcesException; import android.util.Slog; +import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; @@ -95,6 +96,19 @@ class WindowSurfaceController { mSurfaceControl = new SurfaceControl( s, name, w, h, format, flags); } + + if (animator.mService.mSurfaceTraceEnabled) { + mSurfaceControl = new RemoteSurfaceTrace(animator.mService.mSurfaceTraceFd.getFileDescriptor(), + mSurfaceControl, animator.mWin); + } + } + + void installRemoteTrace(FileDescriptor fd) { + mSurfaceControl = new RemoteSurfaceTrace(fd, mSurfaceControl, mAnimator.mWin); + } + + void removeRemoteTrace() { + mSurfaceControl = new SurfaceControl(mSurfaceControl); } diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java index 6ca13d68c316..4a70060d5097 100644 --- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java +++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java @@ -30,6 +30,7 @@ import android.graphics.Bitmap; import android.os.Bundle; import android.os.IBinder; import android.os.IRemoteCallback; +import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.util.DisplayMetrics; import android.view.AppTransitionAnimationSpec; @@ -610,4 +611,12 @@ public class IWindowManagerImpl implements IWindowManager { public Bitmap screenshotWallpaper() throws RemoteException { return null; } + + @Override + public void enableSurfaceTrace(ParcelFileDescriptor fd) throws RemoteException { + } + + @Override + public void disableSurfaceTrace() throws RemoteException { + } } |