Improve testibility of applicatin switches.

Things can be flaky, because window focus changes are
dispatched to the window on a separate path from input events,
and the window will drop events if it gets them before it sees
the focus change.  I am trying to mitigate this some by noting
ASAP what the next upcoming focus state will be, so we can check
that and dispatch it before dispatching a key event if needed.

This definitely makes things better, but not perfect.  ctate
suggested that maybe we should be dispatching window focus events
through the input system, which at a glance sounds like a really
really good idea to me...  so maybe we can look at that later.

Also changed the wm command to just be a shell wrapper around
all of the implementation that is now in WindowManagerShellCommand.

And fixed a few places where we write debug info to streams that
would trigger strict mode violations that we really don't care
about.

Test: manual
Change-Id: I5235653bcec5522ab84c7f2e1de96d86f2f59326
diff --git a/cmds/wm/Android.mk b/cmds/wm/Android.mk
index 3f3795f..693c6e7 100644
--- a/cmds/wm/Android.mk
+++ b/cmds/wm/Android.mk
@@ -3,11 +3,6 @@
 LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_MODULE := wm
-include $(BUILD_JAVA_LIBRARY)
-
-include $(CLEAR_VARS)
 LOCAL_MODULE := wm
 LOCAL_SRC_FILES := wm
 LOCAL_MODULE_CLASS := EXECUTABLES
diff --git a/cmds/wm/src/com/android/commands/wm/Wm.java b/cmds/wm/src/com/android/commands/wm/Wm.java
deleted file mode 100644
index 8defb33..0000000
--- a/cmds/wm/src/com/android/commands/wm/Wm.java
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
-**
-** Copyright 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 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;
-
-public class Wm extends BaseCommand {
-
-    private IWindowManager mWm;
-
-    /**
-     * Command-line entry point.
-     *
-     * @param args The command-line arguments
-     */
-    public static void main(String[] args) {
-        (new Wm()).run(args);
-    }
-
-    @Override
-    public void onShowUsage(PrintStream out) {
-        out.println(
-                "usage: wm [subcommand] [options]\n" +
-                "       wm size [reset|WxH|WdpxHdp]\n" +
-                "       wm density [reset|DENSITY]\n" +
-                "       wm overscan [reset|LEFT,TOP,RIGHT,BOTTOM]\n" +
-                "       wm scaling [off|auto]\n" +
-                "       wm screen-capture [userId] [true|false]\n" +
-                "\n" +
-                "wm size: return or override display size.\n" +
-                "         width and height in pixels unless suffixed with 'dp'.\n" +
-                "\n" +
-                "wm density: override display density.\n" +
-                "\n" +
-                "wm overscan: set overscan area for display.\n" +
-                "\n" +
-                "wm scaling: set display scaling mode.\n" +
-                "\n" +
-                "wm screen-capture: enable/disable screen capture.\n" +
-                "\n" +
-                "wm dismiss-keyguard: dismiss the keyguard, prompting the user for auth if " +
-                "necessary.\n" +
-                "\n" +
-                "wm surface-trace: log surface commands to stdout in a binary format.\n"
-                );
-    }
-
-    @Override
-    public void onRun() throws Exception {
-        mWm = IWindowManager.Stub.asInterface(ServiceManager.checkService(
-                        Context.WINDOW_SERVICE));
-        if (mWm == null) {
-            System.err.println(NO_SYSTEM_ERROR_CODE);
-            throw new AndroidException("Can't connect to window manager; is the system running?");
-        }
-
-        String op = nextArgRequired();
-
-        if (op.equals("size")) {
-            runDisplaySize();
-        } else if (op.equals("density")) {
-            runDisplayDensity();
-        } else if (op.equals("overscan")) {
-            runDisplayOverscan();
-        } else if (op.equals("scaling")) {
-            runDisplayScaling();
-        } else if (op.equals("screen-capture")) {
-            runSetScreenCapture();
-        } else if (op.equals("dismiss-keyguard")) {
-            runDismissKeyguard();
-        } else if (op.equals("surface-trace")) {
-            runSurfaceTrace();
-        } else {
-            showError("Error: unknown command '" + op + "'");
-            return;
-        }
-    }
-
-    private void runSurfaceTrace() throws Exception {
-        ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(FileDescriptor.out);
-        mWm.enableSurfaceTrace(pfd);
-
-        try {
-            // No one is going to wake us up, we are just waiting on SIGINT. Otherwise
-            // the WM can happily continue writing to our stdout.
-            synchronized (this) {
-                this.wait();
-            }
-        } finally {
-            mWm.disableSurfaceTrace();
-        }
-    }
-
-    private void runSetScreenCapture() throws Exception {
-        String userIdStr = nextArg();
-        String enableStr = nextArg();
-        int userId;
-        boolean disable;
-
-        try {
-            userId = Integer.parseInt(userIdStr);
-        } catch (NumberFormatException e) {
-            System.err.println("Error: bad number " + e);
-            return;
-        }
-
-        disable = !Boolean.parseBoolean(enableStr);
-
-        try {
-            mWm.setScreenCaptureDisabled(userId, disable);
-        } catch (RemoteException e) {
-            System.err.println("Error: Can't set screen capture " + e);
-        }
-    }
-
-    private void runDisplaySize() throws Exception {
-        String size = nextArg();
-        int w, h;
-        if (size == null) {
-            Point initialSize = new Point();
-            Point baseSize = new Point();
-            try {
-                mWm.getInitialDisplaySize(Display.DEFAULT_DISPLAY, initialSize);
-                mWm.getBaseDisplaySize(Display.DEFAULT_DISPLAY, baseSize);
-                System.out.println("Physical size: " + initialSize.x + "x" + initialSize.y);
-                if (!initialSize.equals(baseSize)) {
-                    System.out.println("Override size: " + baseSize.x + "x" + baseSize.y);
-                }
-            } catch (RemoteException e) {
-            }
-            return;
-        } else if ("reset".equals(size)) {
-            w = h = -1;
-        } else {
-            int div = size.indexOf('x');
-            if (div <= 0 || div >= (size.length()-1)) {
-                System.err.println("Error: bad size " + size);
-                return;
-            }
-            String wstr = size.substring(0, div);
-            String hstr = size.substring(div+1);
-            try {
-                w = parseDimension(wstr);
-                h = parseDimension(hstr);
-            } catch (NumberFormatException e) {
-                System.err.println("Error: bad number " + e);
-                return;
-            }
-        }
-
-        try {
-            if (w >= 0 && h >= 0) {
-                // TODO(multidisplay): For now Configuration only applies to main screen.
-                mWm.setForcedDisplaySize(Display.DEFAULT_DISPLAY, w, h);
-            } else {
-                mWm.clearForcedDisplaySize(Display.DEFAULT_DISPLAY);
-            }
-        } catch (RemoteException e) {
-        }
-    }
-
-    private void runDisplayDensity() throws Exception {
-        String densityStr = nextArg();
-        int density;
-        if (densityStr == null) {
-            try {
-                int initialDensity = mWm.getInitialDisplayDensity(Display.DEFAULT_DISPLAY);
-                int baseDensity = mWm.getBaseDisplayDensity(Display.DEFAULT_DISPLAY);
-                System.out.println("Physical density: " + initialDensity);
-                if (initialDensity != baseDensity) {
-                    System.out.println("Override density: " + baseDensity);
-                }
-            } catch (RemoteException e) {
-            }
-            return;
-        } else if ("reset".equals(densityStr)) {
-            density = -1;
-        } else {
-            try {
-                density = Integer.parseInt(densityStr);
-            } catch (NumberFormatException e) {
-                System.err.println("Error: bad number " + e);
-                return;
-            }
-            if (density < 72) {
-                System.err.println("Error: density must be >= 72");
-                return;
-            }
-        }
-
-        try {
-            if (density > 0) {
-                // TODO(multidisplay): For now Configuration only applies to main screen.
-                mWm.setForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY, density,
-                        UserHandle.USER_CURRENT);
-            } else {
-                mWm.clearForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY,
-                        UserHandle.USER_CURRENT);
-            }
-        } catch (RemoteException e) {
-        }
-    }
-
-    private void runDisplayOverscan() throws Exception {
-        String overscanStr = nextArgRequired();
-        Rect rect = new Rect();
-        if ("reset".equals(overscanStr)) {
-            rect.set(0, 0, 0, 0);
-        } else {
-            final Pattern FLATTENED_PATTERN = Pattern.compile(
-                    "(-?\\d+),(-?\\d+),(-?\\d+),(-?\\d+)");
-            Matcher matcher = FLATTENED_PATTERN.matcher(overscanStr);
-            if (!matcher.matches()) {
-                System.err.println("Error: bad rectangle arg: " + overscanStr);
-                return;
-            }
-            rect.left = Integer.parseInt(matcher.group(1));
-            rect.top = Integer.parseInt(matcher.group(2));
-            rect.right = Integer.parseInt(matcher.group(3));
-            rect.bottom = Integer.parseInt(matcher.group(4));
-        }
-
-        try {
-            mWm.setOverscan(Display.DEFAULT_DISPLAY, rect.left, rect.top, rect.right, rect.bottom);
-        } catch (RemoteException e) {
-        }
-    }
-
-    private void runDisplayScaling() throws Exception {
-        String scalingStr = nextArgRequired();
-        if ("auto".equals(scalingStr)) {
-            mWm.setForcedDisplayScalingMode(Display.DEFAULT_DISPLAY, 0);
-        } else if ("off".equals(scalingStr)) {
-            mWm.setForcedDisplayScalingMode(Display.DEFAULT_DISPLAY, 1);
-        } else {
-            System.err.println("Error: scaling must be 'auto' or 'off'");
-        }
-    }
-
-    private void runDismissKeyguard() throws Exception {
-        mWm.dismissKeyguard(null /* callback */);
-    }
-
-    private int parseDimension(String s) throws NumberFormatException {
-        if (s.endsWith("px")) {
-            return Integer.parseInt(s.substring(0, s.length() - 2));
-        }
-        if (s.endsWith("dp")) {
-            int density;
-            try {
-                density = mWm.getBaseDisplayDensity(Display.DEFAULT_DISPLAY);
-            } catch (RemoteException e) {
-                density = DisplayMetrics.DENSITY_DEFAULT;
-            }
-            return Integer.parseInt(s.substring(0, s.length() - 2)) * density /
-                    DisplayMetrics.DENSITY_DEFAULT;
-        }
-        return Integer.parseInt(s);
-    }
-}
diff --git a/cmds/wm/wm b/cmds/wm/wm
index 16d6bd6..cb45be2 100755
--- a/cmds/wm/wm
+++ b/cmds/wm/wm
@@ -1,7 +1,2 @@
 #!/system/bin/sh
-# Script to start "wm" on the device, which has a very rudimentary
-# shell.
-#
-base=/system
-export CLASSPATH=$base/framework/wm.jar
-exec app_process $base/bin com.android.commands.wm.Wm "$@"
+cmd window "$@"
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 129a255..adfc1ba 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -323,6 +323,13 @@
     final Rect mTempRect; // used in the transaction to not thrash the heap.
     final Rect mVisRect; // used to retrieve visible rect of focused view.
 
+    // This is used to reduce the race between window focus changes being dispatched from
+    // the window manager and input events coming through the input system.
+    @GuardedBy("this")
+    boolean mUpcomingWindowFocus;
+    @GuardedBy("this")
+    boolean mUpcomingInTouchMode;
+
     public boolean mTraversalScheduled;
     int mTraversalBarrier;
     boolean mWillDrawSoon;
@@ -2452,6 +2459,93 @@
         }
     }
 
+    private void handleWindowFocusChanged() {
+        final boolean hasWindowFocus;
+        final boolean inTouchMode;
+        synchronized (this) {
+            hasWindowFocus = mUpcomingWindowFocus;
+            inTouchMode = mUpcomingInTouchMode;
+        }
+
+        if (mAttachInfo.mHasWindowFocus == hasWindowFocus) {
+            return;
+        }
+
+        if (mAdded) {
+            profileRendering(hasWindowFocus);
+
+            if (hasWindowFocus) {
+                ensureTouchModeLocally(inTouchMode);
+                if (mAttachInfo.mThreadedRenderer != null && mSurface.isValid()) {
+                    mFullRedrawNeeded = true;
+                    try {
+                        final WindowManager.LayoutParams lp = mWindowAttributes;
+                        final Rect surfaceInsets = lp != null ? lp.surfaceInsets : null;
+                        mAttachInfo.mThreadedRenderer.initializeIfNeeded(
+                                mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
+                    } catch (OutOfResourcesException e) {
+                        Log.e(mTag, "OutOfResourcesException locking surface", e);
+                        try {
+                            if (!mWindowSession.outOfMemory(mWindow)) {
+                                Slog.w(mTag, "No processes killed for memory;"
+                                        + " killing self");
+                                Process.killProcess(Process.myPid());
+                            }
+                        } catch (RemoteException ex) {
+                        }
+                        // Retry in a bit.
+                        mHandler.sendMessageDelayed(mHandler.obtainMessage(
+                                MSG_WINDOW_FOCUS_CHANGED), 500);
+                        return;
+                    }
+                }
+            }
+
+            mAttachInfo.mHasWindowFocus = hasWindowFocus;
+
+            mLastWasImTarget = WindowManager.LayoutParams
+                    .mayUseInputMethod(mWindowAttributes.flags);
+
+            InputMethodManager imm = InputMethodManager.peekInstance();
+            if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
+                imm.onPreWindowFocus(mView, hasWindowFocus);
+            }
+            if (mView != null) {
+                mAttachInfo.mKeyDispatchState.reset();
+                mView.dispatchWindowFocusChanged(hasWindowFocus);
+                mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus);
+
+                if (mAttachInfo.mTooltipHost != null) {
+                    mAttachInfo.mTooltipHost.hideTooltip();
+                }
+            }
+
+            // Note: must be done after the focus change callbacks,
+            // so all of the view state is set up correctly.
+            if (hasWindowFocus) {
+                if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
+                    imm.onPostWindowFocus(mView, mView.findFocus(),
+                            mWindowAttributes.softInputMode,
+                            !mHasHadWindowFocus, mWindowAttributes.flags);
+                }
+                // Clear the forward bit.  We can just do this directly, since
+                // the window manager doesn't care about it.
+                mWindowAttributes.softInputMode &=
+                        ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
+                ((WindowManager.LayoutParams) mView.getLayoutParams())
+                        .softInputMode &=
+                        ~WindowManager.LayoutParams
+                                .SOFT_INPUT_IS_FORWARD_NAVIGATION;
+                mHasHadWindowFocus = true;
+            } else {
+                if (mPointerCapture) {
+                    handlePointerCaptureChanged(false);
+                }
+            }
+        }
+        mFirstInputStage.onWindowFocusChanged(hasWindowFocus);
+    }
+
     private void handleOutOfResourcesException(Surface.OutOfResourcesException e) {
         Log.e(mTag, "OutOfResourcesException initializing HW surface", e);
         try {
@@ -3900,81 +3994,7 @@
                     }
                     break;
                 case MSG_WINDOW_FOCUS_CHANGED: {
-                    final boolean hasWindowFocus = msg.arg1 != 0;
-                    if (mAdded) {
-                        mAttachInfo.mHasWindowFocus = hasWindowFocus;
-
-                        profileRendering(hasWindowFocus);
-
-                        if (hasWindowFocus) {
-                            boolean inTouchMode = msg.arg2 != 0;
-                            ensureTouchModeLocally(inTouchMode);
-                            if (mAttachInfo.mThreadedRenderer != null && mSurface.isValid()) {
-                                mFullRedrawNeeded = true;
-                                try {
-                                    final WindowManager.LayoutParams lp = mWindowAttributes;
-                                    final Rect surfaceInsets = lp != null ? lp.surfaceInsets : null;
-                                    mAttachInfo.mThreadedRenderer.initializeIfNeeded(
-                                            mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
-                                } catch (OutOfResourcesException e) {
-                                    Log.e(mTag, "OutOfResourcesException locking surface", e);
-                                    try {
-                                        if (!mWindowSession.outOfMemory(mWindow)) {
-                                            Slog.w(mTag, "No processes killed for memory;"
-                                                    + " killing self");
-                                            Process.killProcess(Process.myPid());
-                                        }
-                                    } catch (RemoteException ex) {
-                                    }
-                                    // Retry in a bit.
-                                    sendMessageDelayed(obtainMessage(msg.what, msg.arg1, msg.arg2),
-                                            500);
-                                    return;
-                                }
-                            }
-                        }
-
-                        mLastWasImTarget = WindowManager.LayoutParams
-                                .mayUseInputMethod(mWindowAttributes.flags);
-
-                        InputMethodManager imm = InputMethodManager.peekInstance();
-                        if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
-                            imm.onPreWindowFocus(mView, hasWindowFocus);
-                        }
-                        if (mView != null) {
-                            mAttachInfo.mKeyDispatchState.reset();
-                            mView.dispatchWindowFocusChanged(hasWindowFocus);
-                            mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus);
-
-                            if (mAttachInfo.mTooltipHost != null) {
-                                mAttachInfo.mTooltipHost.hideTooltip();
-                            }
-                        }
-
-                        // Note: must be done after the focus change callbacks,
-                        // so all of the view state is set up correctly.
-                        if (hasWindowFocus) {
-                            if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
-                                imm.onPostWindowFocus(mView, mView.findFocus(),
-                                        mWindowAttributes.softInputMode,
-                                        !mHasHadWindowFocus, mWindowAttributes.flags);
-                            }
-                            // Clear the forward bit.  We can just do this directly, since
-                            // the window manager doesn't care about it.
-                            mWindowAttributes.softInputMode &=
-                                    ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
-                            ((WindowManager.LayoutParams) mView.getLayoutParams())
-                                    .softInputMode &=
-                                        ~WindowManager.LayoutParams
-                                                .SOFT_INPUT_IS_FORWARD_NAVIGATION;
-                            mHasHadWindowFocus = true;
-                        } else {
-                            if (mPointerCapture) {
-                                handlePointerCaptureChanged(false);
-                            }
-                        }
-                    }
-                    mFirstInputStage.onWindowFocusChanged(hasWindowFocus);
+                    handleWindowFocusChanged();
                 } break;
                 case MSG_DIE:
                     doDie();
@@ -6845,6 +6865,7 @@
         }
 
         if (stage != null) {
+            handleWindowFocusChanged();
             stage.deliver(q);
         } else {
             finishInputEvent(q);
@@ -7150,10 +7171,12 @@
     }
 
     public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
+        synchronized (this) {
+            mUpcomingWindowFocus = hasFocus;
+            mUpcomingInTouchMode = inTouchMode;
+        }
         Message msg = Message.obtain();
         msg.what = MSG_WINDOW_FOCUS_CHANGED;
-        msg.arg1 = hasFocus ? 1 : 0;
-        msg.arg2 = inTouchMode ? 1 : 0;
         mHandler.sendMessage(msg);
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 979323f..51121fb 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -48,6 +48,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.ShellCommand;
+import android.os.StrictMode;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
@@ -126,7 +127,7 @@
         if (cmd == null) {
             return handleDefaultCommands(cmd);
         }
-        PrintWriter pw = getOutPrintWriter();
+        final PrintWriter pw = getOutPrintWriter();
         try {
             switch (cmd) {
                 case "start":
@@ -1326,65 +1327,95 @@
         @Override
         public void onUidStateChanged(int uid, int procState, long procStateSeq) throws RemoteException {
             synchronized (this) {
-                mPw.print(uid);
-                mPw.print(" procstate ");
-                mPw.print(ProcessList.makeProcStateString(procState));
-                mPw.print(" seq ");
-                mPw.println(procStateSeq);
-                mPw.flush();
+                final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
+                try {
+                    mPw.print(uid);
+                    mPw.print(" procstate ");
+                    mPw.print(ProcessList.makeProcStateString(procState));
+                    mPw.print(" seq ");
+                    mPw.println(procStateSeq);
+                    mPw.flush();
+                } finally {
+                    StrictMode.setThreadPolicy(oldPolicy);
+                }
             }
         }
 
         @Override
         public void onUidGone(int uid, boolean disabled) throws RemoteException {
             synchronized (this) {
-                mPw.print(uid);
-                mPw.print(" gone");
-                if (disabled) {
-                    mPw.print(" disabled");
+                final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
+                try {
+                    mPw.print(uid);
+                    mPw.print(" gone");
+                    if (disabled) {
+                        mPw.print(" disabled");
+                    }
+                    mPw.println();
+                    mPw.flush();
+                } finally {
+                    StrictMode.setThreadPolicy(oldPolicy);
                 }
-                mPw.println();
-                mPw.flush();
             }
         }
 
         @Override
         public void onUidActive(int uid) throws RemoteException {
             synchronized (this) {
-                mPw.print(uid);
-                mPw.println(" active");
-                mPw.flush();
+                final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
+                try {
+                    mPw.print(uid);
+                    mPw.println(" active");
+                    mPw.flush();
+                } finally {
+                    StrictMode.setThreadPolicy(oldPolicy);
+                }
             }
         }
 
         @Override
         public void onUidIdle(int uid, boolean disabled) throws RemoteException {
             synchronized (this) {
-                mPw.print(uid);
-                mPw.print(" idle");
-                if (disabled) {
-                    mPw.print(" disabled");
+                final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
+                try {
+                    mPw.print(uid);
+                    mPw.print(" idle");
+                    if (disabled) {
+                        mPw.print(" disabled");
+                    }
+                    mPw.println();
+                    mPw.flush();
+                } finally {
+                    StrictMode.setThreadPolicy(oldPolicy);
                 }
-                mPw.println();
-                mPw.flush();
             }
         }
 
         @Override
         public void onUidCachedChanged(int uid, boolean cached) throws RemoteException {
             synchronized (this) {
-                mPw.print(uid);
-                mPw.println(cached ? " cached" : " uncached");
-                mPw.flush();
+                final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
+                try {
+                    mPw.print(uid);
+                    mPw.println(cached ? " cached" : " uncached");
+                    mPw.flush();
+                } finally {
+                    StrictMode.setThreadPolicy(oldPolicy);
+                }
             }
         }
 
         @Override
         public void onOomAdjMessage(String msg) {
             synchronized (this) {
-                mPw.print("# ");
-                mPw.println(msg);
-                mPw.flush();
+                final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
+                try {
+                    mPw.print("# ");
+                    mPw.println(msg);
+                    mPw.flush();
+                } finally {
+                    StrictMode.setThreadPolicy(oldPolicy);
+                }
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/RemoteEventTrace.java b/services/core/java/com/android/server/wm/RemoteEventTrace.java
index 9f65ba3..b214d35 100644
--- a/services/core/java/com/android/server/wm/RemoteEventTrace.java
+++ b/services/core/java/com/android/server/wm/RemoteEventTrace.java
@@ -20,6 +20,7 @@
 import java.io.FileOutputStream;
 import java.io.DataOutputStream;
 
+import android.os.StrictMode;
 import android.util.Slog;
 import android.os.Debug;
 
@@ -40,22 +41,28 @@
     }
 
     void openSurfaceTransaction() {
+        final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
         try {
             mOut.writeUTF("OpenTransaction");
             writeSigil();
         } catch (Exception e) {
             logException(e);
             mService.disableSurfaceTrace();
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
         }
     }
 
     void closeSurfaceTransaction() {
+        final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
         try {
             mOut.writeUTF("CloseTransaction");
             writeSigil();
         } catch (Exception e) {
             logException(e);
             mService.disableSurfaceTrace();
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/RemoteSurfaceTrace.java b/services/core/java/com/android/server/wm/RemoteSurfaceTrace.java
index a12c2c4..d2cbf88 100644
--- a/services/core/java/com/android/server/wm/RemoteSurfaceTrace.java
+++ b/services/core/java/com/android/server/wm/RemoteSurfaceTrace.java
@@ -20,6 +20,7 @@
 import android.graphics.Region;
 import android.os.IBinder;
 import android.os.Parcel;
+import android.os.StrictMode;
 import android.util.Slog;
 import android.view.SurfaceControl;
 
@@ -54,67 +55,122 @@
 
     @Override
     public void setAlpha(float alpha) {
-        writeFloatEvent("Alpha", alpha);
+        final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
+        try {
+            writeFloatEvent("Alpha", alpha);
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
+        }
         super.setAlpha(alpha);
     }
 
     @Override
     public void setLayer(int zorder) {
-        writeIntEvent("Layer", zorder);
+        final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
+        try {
+            writeIntEvent("Layer", zorder);
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
+        }
         super.setLayer(zorder);
     }
 
     @Override
     public void setPosition(float x, float y) {
-        writeFloatEvent("Position", x, y);
+        final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
+        try {
+            writeFloatEvent("Position", x, y);
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
+        }
         super.setPosition(x, y);
     }
 
     @Override
     public void setGeometryAppliesWithResize() {
-        writeEvent("GeometryAppliesWithResize");
+        final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
+        try {
+            writeEvent("GeometryAppliesWithResize");
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
+        }
         super.setGeometryAppliesWithResize();
     }
 
     @Override
     public void setSize(int w, int h) {
-        writeIntEvent("Size", w, h);
+        final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
+        try {
+            writeIntEvent("Size", w, h);
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
+        }
         super.setSize(w, h);
     }
 
     @Override
     public void setWindowCrop(Rect crop) {
-        writeRectEvent("Crop", crop);
+        final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
+        try {
+            writeRectEvent("Crop", crop);
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
+        }
         super.setWindowCrop(crop);
     }
 
     @Override
     public void setFinalCrop(Rect crop) {
-        writeRectEvent("FinalCrop", crop);
+        final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
+        try {
+            writeRectEvent("FinalCrop", crop);
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
+        }
         super.setFinalCrop(crop);
     }
 
     @Override
     public void setLayerStack(int layerStack) {
-        writeIntEvent("LayerStack", layerStack);
+        final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
+        try {
+            writeIntEvent("LayerStack", layerStack);
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
+        }
         super.setLayerStack(layerStack);
     }
 
     @Override
     public void setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
-        writeFloatEvent("Matrix", dsdx, dtdx, dsdy, dtdy);
+        final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
+        try {
+            writeFloatEvent("Matrix", dsdx, dtdx, dsdy, dtdy);
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
+        }
         super.setMatrix(dsdx, dtdx, dsdy, dtdy);
     }
 
     @Override
     public void hide() {
-        writeEvent("Hide");
+        final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
+        try {
+            writeEvent("Hide");
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
+        }
         super.hide();
     }
 
     @Override
     public void show() {
-        writeEvent("Show");
+        final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
+        try {
+            writeEvent("Show");
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
+        }
         super.show();
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index 2358695..b9dc9db 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -18,9 +18,23 @@
 
 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.view.Display;
+import android.view.IWindowManager;
 
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.io.PrintWriter;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * ShellCommands for WindowManagerService.
@@ -29,33 +43,279 @@
  */
 public class WindowManagerShellCommand extends ShellCommand {
 
-    private final WindowManagerService mService;
+    // IPC interface to activity manager -- don't need to do additional security checks.
+    private final IWindowManager mInterface;
+
+    // Internal service impl -- must perform security checks before touching.
+    private final WindowManagerService mInternal;
 
     public WindowManagerShellCommand(WindowManagerService service) {
-        mService = service;
+        mInterface = service;
+        mInternal = service;
     }
 
     @Override
     public int onCommand(String cmd) {
-        switch (cmd) {
-            case "tracing":
-                return mService.mWindowTracing.onShellCommand(this, getNextArgRequired());
-            default:
-                return handleDefaultCommands(cmd);
+        if (cmd == null) {
+            return handleDefaultCommands(cmd);
         }
+        final PrintWriter pw = getOutPrintWriter();
+        try {
+            switch (cmd) {
+                case "size":
+                    return runDisplaySize(pw);
+                case "density":
+                    return runDisplayDensity(pw);
+                case "overscan":
+                    return runDisplayOverscan(pw);
+                case "scaling":
+                    return runDisplayScaling(pw);
+                case "screen-capture":
+                    return runSetScreenCapture(pw);
+                case "dismiss-keyguard":
+                    return runDismissKeyguard(pw);
+                case "surface-trace":
+                    return runSurfaceTrace(pw);
+                case "tracing":
+                    // XXX this should probably be changed to use openFileForSystem() to create
+                    // the output trace file, so the shell gets the correct semantics for where
+                    // trace files can be written.
+                    return mInternal.mWindowTracing.onShellCommand(this,
+                            getNextArgRequired());
+                default:
+                    return handleDefaultCommands(cmd);
+            }
+        } catch (RemoteException e) {
+            pw.println("Remote exception: " + e);
+        }
+        return -1;
+    }
+
+    private int runDisplaySize(PrintWriter pw) throws RemoteException {
+        String size = getNextArg();
+        int w, h;
+        if (size == null) {
+            Point initialSize = new Point();
+            Point baseSize = new Point();
+            try {
+                mInterface.getInitialDisplaySize(Display.DEFAULT_DISPLAY, initialSize);
+                mInterface.getBaseDisplaySize(Display.DEFAULT_DISPLAY, baseSize);
+                pw.println("Physical size: " + initialSize.x + "x" + initialSize.y);
+                if (!initialSize.equals(baseSize)) {
+                    pw.println("Override size: " + baseSize.x + "x" + baseSize.y);
+                }
+            } catch (RemoteException e) {
+            }
+            return 0;
+        } else if ("reset".equals(size)) {
+            w = h = -1;
+        } else {
+            int div = size.indexOf('x');
+            if (div <= 0 || div >= (size.length()-1)) {
+                getErrPrintWriter().println("Error: bad size " + size);
+                return -1;
+            }
+            String wstr = size.substring(0, div);
+            String hstr = size.substring(div+1);
+            try {
+                w = parseDimension(wstr);
+                h = parseDimension(hstr);
+            } catch (NumberFormatException e) {
+                getErrPrintWriter().println("Error: bad number " + e);
+                return -1;
+            }
+        }
+
+        if (w >= 0 && h >= 0) {
+            // TODO(multidisplay): For now Configuration only applies to main screen.
+            mInterface.setForcedDisplaySize(Display.DEFAULT_DISPLAY, w, h);
+        } else {
+            mInterface.clearForcedDisplaySize(Display.DEFAULT_DISPLAY);
+        }
+        return 0;
+    }
+
+    private int runDisplayDensity(PrintWriter pw) throws RemoteException {
+        String densityStr = getNextArg();
+        int density;
+        if (densityStr == null) {
+            try {
+                int initialDensity = mInterface.getInitialDisplayDensity(Display.DEFAULT_DISPLAY);
+                int baseDensity = mInterface.getBaseDisplayDensity(Display.DEFAULT_DISPLAY);
+                pw.println("Physical density: " + initialDensity);
+                if (initialDensity != baseDensity) {
+                    pw.println("Override density: " + baseDensity);
+                }
+            } catch (RemoteException e) {
+            }
+            return 0;
+        } else if ("reset".equals(densityStr)) {
+            density = -1;
+        } else {
+            try {
+                density = Integer.parseInt(densityStr);
+            } catch (NumberFormatException e) {
+                getErrPrintWriter().println("Error: bad number " + e);
+                return -1;
+            }
+            if (density < 72) {
+                getErrPrintWriter().println("Error: density must be >= 72");
+                return -1;
+            }
+        }
+
+        if (density > 0) {
+            // TODO(multidisplay): For now Configuration only applies to main screen.
+            mInterface.setForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY, density,
+                    UserHandle.USER_CURRENT);
+        } else {
+            mInterface.clearForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY,
+                    UserHandle.USER_CURRENT);
+        }
+        return 0;
+    }
+
+    private int runDisplayOverscan(PrintWriter pw) throws RemoteException {
+        String overscanStr = getNextArgRequired();
+        Rect rect = new Rect();
+        if ("reset".equals(overscanStr)) {
+            rect.set(0, 0, 0, 0);
+        } else {
+            final Pattern FLATTENED_PATTERN = Pattern.compile(
+                    "(-?\\d+),(-?\\d+),(-?\\d+),(-?\\d+)");
+            Matcher matcher = FLATTENED_PATTERN.matcher(overscanStr);
+            if (!matcher.matches()) {
+                getErrPrintWriter().println("Error: bad rectangle arg: " + overscanStr);
+                return -1;
+            }
+            rect.left = Integer.parseInt(matcher.group(1));
+            rect.top = Integer.parseInt(matcher.group(2));
+            rect.right = Integer.parseInt(matcher.group(3));
+            rect.bottom = Integer.parseInt(matcher.group(4));
+        }
+
+        mInterface.setOverscan(Display.DEFAULT_DISPLAY, rect.left, rect.top, rect.right,
+                rect.bottom);
+        return 0;
+    }
+
+    private int runDisplayScaling(PrintWriter pw) throws RemoteException {
+        String scalingStr = getNextArgRequired();
+        if ("auto".equals(scalingStr)) {
+            mInterface.setForcedDisplayScalingMode(Display.DEFAULT_DISPLAY, 0);
+        } else if ("off".equals(scalingStr)) {
+            mInterface.setForcedDisplayScalingMode(Display.DEFAULT_DISPLAY, 1);
+        } else {
+            getErrPrintWriter().println("Error: scaling must be 'auto' or 'off'");
+            return -1;
+        }
+        return 0;
+    }
+
+    private int runSetScreenCapture(PrintWriter pw) throws RemoteException {
+        String userIdStr = getNextArg();
+        String enableStr = getNextArg();
+        int userId;
+        boolean disable;
+
+        try {
+            userId = Integer.parseInt(userIdStr);
+        } catch (NumberFormatException e) {
+            getErrPrintWriter().println("Error: bad number " + e);
+            return -1;
+        }
+
+        disable = !Boolean.parseBoolean(enableStr);
+        mInternal.setScreenCaptureDisabled(userId, disable);
+        return 0;
+    }
+
+    private int runDismissKeyguard(PrintWriter pw) throws RemoteException {
+        mInterface.dismissKeyguard(null /* callback */);
+        return 0;
+    }
+
+    private int runSurfaceTrace(PrintWriter pw) throws RemoteException {
+        final ParcelFileDescriptor pfd;
+        try {
+            pfd = ParcelFileDescriptor.dup(getOutFileDescriptor());
+        } catch (IOException e) {
+            getErrPrintWriter().println("Unable to dup output stream: " + e.getMessage());
+            return -1;
+        }
+        mInternal.enableSurfaceTrace(pfd);
+
+        // Read input until an explicit quit command is sent or the stream is closed (meaning
+        // the user killed the command).
+        try {
+            InputStream input = getRawInputStream();
+            InputStreamReader converter = new InputStreamReader(input);
+            BufferedReader in = new BufferedReader(converter);
+            String line;
+
+            while ((line = in.readLine()) != null) {
+                if (line.length() <= 0) {
+                    // no-op
+                } else if ("q".equals(line) || "quit".equals(line)) {
+                    break;
+                } else {
+                    pw.println("Invalid command: " + line);
+                }
+            }
+        } catch (IOException e) {
+            e.printStackTrace(pw);
+        } finally {
+            mInternal.disableSurfaceTrace();
+            try {
+                pfd.close();
+            } catch (IOException e) {
+            }
+        }
+
+        return 0;
+    }
+
+    private int parseDimension(String s) throws NumberFormatException {
+        if (s.endsWith("px")) {
+            return Integer.parseInt(s.substring(0, s.length() - 2));
+        }
+        if (s.endsWith("dp")) {
+            int density;
+            try {
+                density = mInterface.getBaseDisplayDensity(Display.DEFAULT_DISPLAY);
+            } catch (RemoteException e) {
+                density = DisplayMetrics.DENSITY_DEFAULT;
+            }
+            return Integer.parseInt(s.substring(0, s.length() - 2)) * density /
+                    DisplayMetrics.DENSITY_DEFAULT;
+        }
+        return Integer.parseInt(s);
     }
 
     @Override
     public void onHelp() {
         PrintWriter pw = getOutPrintWriter();
-        pw.println("Window Manager (window) commands:");
+        pw.println("Window manager (window) commands:");
         pw.println("  help");
-        pw.println("    Print this help text.");
-        pw.println();
-        if (!IS_USER){
+        pw.println("      Print this help text.");
+        pw.println("  size [reset|WxH|WdpxHdp]");
+        pw.println("    Return or override display size.");
+        pw.println("    width and height in pixels unless suffixed with 'dp'.");
+        pw.println("  density [reset|DENSITY]");
+        pw.println("    Return or override display density.");
+        pw.println("  overscan [reset|LEFT,TOP,RIGHT,BOTTOM]");
+        pw.println("    Set overscan area for display.");
+        pw.println("  scaling [off|auto]");
+        pw.println("    Set display scaling mode.");
+        pw.println("  screen-capture [userId] [true|false]");
+        pw.println("    Enable or disable screen capture.");
+        pw.println("  dismiss-keyguard");
+        pw.println("    Dismiss the keyguard, prompting user for auth if necessary.");
+        pw.println("  surface-trace");
+        pw.println("    Log surface commands to stdout in a binary format.");
+        if (!IS_USER) {
             pw.println("  tracing (start | stop)");
-            pw.println("    start or stop window tracing");
-            pw.println();
+            pw.println("    Start or stop window tracing.");
         }
     }
 }