diff options
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 { + } } |