Refactor display manager service to new pattern.

Transform DisplayManagerService into a SystemService and start cleaning
up other local services that it uses from window manager and input manager.

Clean up service thread initialization.

Remove unnecessary static variables from ActivityManagerService.

It's starting to become clear that we really need a better way to manage
service dependencies.  Boot phases don't quite cut it.

Change-Id: If319dbd7cbfbd4812fe55ece969e818d4b20755b
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
new file mode 100644
index 0000000..8430973
--- /dev/null
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2014 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 android.hardware.display;
+
+import android.view.DisplayInfo;
+
+/**
+ * Display manager local system service interface.
+ *
+ * @hide Only for use within the system server.
+ */
+public abstract class DisplayManagerInternal {
+    /**
+     * Called by the power manager to blank all displays.
+     */
+    public abstract void blankAllDisplaysFromPowerManager();
+
+    /**
+     * Called by the power manager to unblank all displays.
+     */
+    public abstract void unblankAllDisplaysFromPowerManager();
+
+    /**
+     * Returns information about the specified logical display.
+     *
+     * @param displayId The logical display id.
+     * @return The logical display info, or null if the display does not exist.  The
+     * returned object must be treated as immutable.
+     */
+    public abstract DisplayInfo getDisplayInfo(int displayId);
+
+    /**
+     * Registers a display transaction listener to provide the client a chance to
+     * update its surfaces within the same transaction as any display layout updates.
+     *
+     * @param listener The listener to register.
+     */
+    public abstract void registerDisplayTransactionListener(DisplayTransactionListener listener);
+
+    /**
+     * Unregisters a display transaction listener to provide the client a chance to
+     * update its surfaces within the same transaction as any display layout updates.
+     *
+     * @param listener The listener to unregister.
+     */
+    public abstract void unregisterDisplayTransactionListener(DisplayTransactionListener listener);
+
+    /**
+     * Overrides the display information of a particular logical display.
+     * This is used by the window manager to control the size and characteristics
+     * of the default display.  It is expected to apply the requested change
+     * to the display information synchronously so that applications will immediately
+     * observe the new state.
+     *
+     * NOTE: This method must be the only entry point by which the window manager
+     * influences the logical configuration of displays.
+     *
+     * @param displayId The logical display id.
+     * @param info The new data to be stored.
+     */
+    public abstract void setDisplayInfoOverrideFromWindowManager(
+            int displayId, DisplayInfo info);
+
+    /**
+     * Called by the window manager to perform traversals while holding a
+     * surface flinger transaction.
+     */
+    public abstract void performTraversalInTransactionFromWindowManager();
+
+    /**
+     * Tells the display manager whether there is interesting unique content on the
+     * specified logical display.  This is used to control automatic mirroring.
+     * <p>
+     * If the display has unique content, then the display manager arranges for it
+     * to be presented on a physical display if appropriate.  Otherwise, the display manager
+     * may choose to make the physical display mirror some other logical display.
+     * </p>
+     *
+     * @param displayId The logical display id to update.
+     * @param hasContent True if the logical display has content.
+     * @param inTraversal True if called from WindowManagerService during a window traversal
+     * prior to call to performTraversalInTransactionFromWindowManager.
+     */
+    public abstract void setDisplayHasContent(int displayId, boolean hasContent,
+            boolean inTraversal);
+
+    /**
+     * Called within a Surface transaction whenever the size or orientation of a
+     * display may have changed.  Provides an opportunity for the client to
+     * update the position of its surfaces as part of the same transaction.
+     */
+    public interface DisplayTransactionListener {
+        void onDisplayTransaction();
+    }
+}
diff --git a/services/core/java/com/android/server/display/DisplayViewport.java b/core/java/android/hardware/display/DisplayViewport.java
similarity index 96%
rename from services/core/java/com/android/server/display/DisplayViewport.java
rename to core/java/android/hardware/display/DisplayViewport.java
index 5080556..c2d498b 100644
--- a/services/core/java/com/android/server/display/DisplayViewport.java
+++ b/core/java/android/hardware/display/DisplayViewport.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.display;
+package android.hardware.display;
 
 import android.graphics.Rect;
 
@@ -25,6 +25,8 @@
  * This information is used by the input system to translate touch input from
  * physical display coordinates into logical display coordinates.
  * </p>
+ *
+ * @hide Only for use within the system server.
  */
 public final class DisplayViewport {
     // True if this viewport is valid.
diff --git a/core/java/android/hardware/input/InputManagerInternal.java b/core/java/android/hardware/input/InputManagerInternal.java
new file mode 100644
index 0000000..ecd32ea
--- /dev/null
+++ b/core/java/android/hardware/input/InputManagerInternal.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2014 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 android.hardware.input;
+
+import android.hardware.display.DisplayViewport;
+
+/**
+ * Input manager local system service interface.
+ *
+ * @hide Only for use within the system server.
+ */
+public abstract class InputManagerInternal {
+    /**
+     * Sets information about the displays as needed by the input system.
+     * The input system should copy this information if required.
+     */
+    public abstract void setDisplayViewports(DisplayViewport defaultViewport,
+            DisplayViewport externalTouchViewport);
+}
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index 8144576..cb3d528 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -23,7 +23,7 @@
  *
  * @hide Only for use within the system server.
  */
-public interface PowerManagerInternal {
+public abstract class PowerManagerInternal {
     /**
      * Used by the window manager to override the screen brightness based on the
      * current foreground activity.
@@ -32,7 +32,7 @@
      *
      * @param brightness The overridden brightness, or -1 to disable the override.
      */
-    public void setScreenBrightnessOverrideFromWindowManager(int brightness);
+    public abstract void setScreenBrightnessOverrideFromWindowManager(int brightness);
 
     /**
      * Used by the window manager to override the button brightness based on the
@@ -42,7 +42,7 @@
      *
      * @param brightness The overridden brightness, or -1 to disable the override.
      */
-    public void setButtonBrightnessOverrideFromWindowManager(int brightness);
+    public abstract void setButtonBrightnessOverrideFromWindowManager(int brightness);
 
     /**
      * Used by the window manager to override the user activity timeout based on the
@@ -53,8 +53,8 @@
      *
      * @param timeoutMillis The overridden timeout, or -1 to disable the override.
      */
-    public void setUserActivityTimeoutOverrideFromWindowManager(long timeoutMillis);
+    public abstract void setUserActivityTimeoutOverrideFromWindowManager(long timeoutMillis);
 
     // TODO: Remove this and retrieve as a local service instead.
-    public void setPolicy(WindowManagerPolicy policy);
+    public abstract void setPolicy(WindowManagerPolicy policy);
 }
diff --git a/core/java/android/view/WindowManagerInternal.java b/core/java/android/view/WindowManagerInternal.java
new file mode 100644
index 0000000..a1bd4bd
--- /dev/null
+++ b/core/java/android/view/WindowManagerInternal.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2014 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 android.view;
+
+import android.hardware.display.DisplayManagerInternal;
+
+/**
+ * Window manager local system service interface.
+ *
+ * @hide Only for use within the system server.
+ */
+public abstract class WindowManagerInternal {
+    /**
+     * Request that the window manager call
+     * {@link DisplayManagerInternal#performTraversalInTransactionFromWindowManager}
+     * within a surface transaction at a later time.
+     */
+    public abstract void requestTraversalFromDisplayManager();
+}
\ No newline at end of file
diff --git a/core/java/com/android/server/SystemService.java b/core/java/com/android/server/SystemService.java
index 0356753..d69293a 100644
--- a/core/java/com/android/server/SystemService.java
+++ b/core/java/com/android/server/SystemService.java
@@ -48,6 +48,7 @@
     /*
      * Boot Phases
      */
+    public static final int PHASE_WAIT_FOR_DEFAULT_DISPLAY = 100; // maybe should be a dependency?
     public static final int PHASE_LOCK_SETTINGS_READY = 480;
     public static final int PHASE_SYSTEM_SERVICES_READY = 500;
     public static final int PHASE_THIRD_PARTY_APPS_CAN_START = 600;
@@ -93,7 +94,15 @@
      * Publish the service so it is accessible to other services and apps.
      */
     protected final void publishBinderService(String name, IBinder service) {
-        ServiceManager.addService(name, service);
+        publishBinderService(name, service, false);
+    }
+
+    /**
+     * Publish the service so it is accessible to other services and apps.
+     */
+    protected final void publishBinderService(String name, IBinder service,
+            boolean allowIsolated) {
+        ServiceManager.addService(name, service, allowIsolated);
     }
 
     /**
diff --git a/services/core/java/com/android/server/DisplayThread.java b/services/core/java/com/android/server/DisplayThread.java
new file mode 100644
index 0000000..528ba0a
--- /dev/null
+++ b/services/core/java/com/android/server/DisplayThread.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 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.server;
+
+import android.os.Handler;
+
+/**
+ * Shared singleton foreground thread for the system.  This is a thread for
+ * operations that affect what's on the display, which needs to have a minimum
+ * of latency.  This thread should pretty much only be used by the WindowManager,
+ * DisplayManager, and InputManager to perform quick operations in real time.
+ */
+public final class DisplayThread extends ServiceThread {
+    private static DisplayThread sInstance;
+    private static Handler sHandler;
+
+    private DisplayThread() {
+        super("android.display", android.os.Process.THREAD_PRIORITY_DISPLAY, false /*allowIo*/);
+    }
+
+    private static void ensureThreadLocked() {
+        if (sInstance == null) {
+            sInstance = new DisplayThread();
+            sInstance.start();
+            sHandler = new Handler(sInstance.getLooper());
+        }
+    }
+
+    public static DisplayThread get() {
+        synchronized (UiThread.class) {
+            ensureThreadLocked();
+            return sInstance;
+        }
+    }
+
+    public static Handler getHandler() {
+        synchronized (UiThread.class) {
+            ensureThreadLocked();
+            return sHandler;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/FgThread.java b/services/core/java/com/android/server/FgThread.java
index 3b655f2..03765db 100644
--- a/services/core/java/com/android/server/FgThread.java
+++ b/services/core/java/com/android/server/FgThread.java
@@ -17,7 +17,6 @@
 package com.android.server;
 
 import android.os.Handler;
-import android.os.HandlerThread;
 
 /**
  * Shared singleton foreground thread for the system.  This is a thread for regular
@@ -27,12 +26,12 @@
  * simply being a background priority), which can cause operations scheduled on it
  * to be delayed for a user-noticeable amount of time.
  */
-public final class FgThread extends HandlerThread {
+public final class FgThread extends ServiceThread {
     private static FgThread sInstance;
     private static Handler sHandler;
 
     private FgThread() {
-        super("android.fg", android.os.Process.THREAD_PRIORITY_DEFAULT);
+        super("android.fg", android.os.Process.THREAD_PRIORITY_DEFAULT, true /*allowIo*/);
     }
 
     private static void ensureThreadLocked() {
@@ -40,12 +39,6 @@
             sInstance = new FgThread();
             sInstance.start();
             sHandler = new Handler(sInstance.getLooper());
-            sHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    android.os.Process.setCanSelfBackground(false);
-                }
-            });
         }
     }
 
diff --git a/services/core/java/com/android/server/IoThread.java b/services/core/java/com/android/server/IoThread.java
index 09f2af7..0f29857 100644
--- a/services/core/java/com/android/server/IoThread.java
+++ b/services/core/java/com/android/server/IoThread.java
@@ -17,19 +17,18 @@
 package com.android.server;
 
 import android.os.Handler;
-import android.os.HandlerThread;
 
 /**
  * Shared singleton I/O thread for the system.  This is a thread for non-background
  * service operations that can potential block briefly on network IO operations
  * (not waiting for data itself, but communicating with network daemons).
  */
-public final class IoThread extends HandlerThread {
+public final class IoThread extends ServiceThread {
     private static IoThread sInstance;
     private static Handler sHandler;
 
     private IoThread() {
-        super("android.io", android.os.Process.THREAD_PRIORITY_DEFAULT);
+        super("android.io", android.os.Process.THREAD_PRIORITY_DEFAULT, true /*allowIo*/);
     }
 
     private static void ensureThreadLocked() {
@@ -37,12 +36,6 @@
             sInstance = new IoThread();
             sInstance.start();
             sHandler = new Handler(sInstance.getLooper());
-            sHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    android.os.Process.setCanSelfBackground(false);
-                }
-            });
         }
     }
 
diff --git a/services/core/java/com/android/server/ServiceThread.java b/services/core/java/com/android/server/ServiceThread.java
index 75ec4ef..bce64af 100644
--- a/services/core/java/com/android/server/ServiceThread.java
+++ b/services/core/java/com/android/server/ServiceThread.java
@@ -24,11 +24,14 @@
 /**
  * Special handler thread that we create for system services that require their own loopers.
  */
-public final class ServiceThread extends HandlerThread {
+public class ServiceThread extends HandlerThread {
     private static final String TAG = "ServiceThread";
 
-    public ServiceThread(String name, int priority) {
+    private final boolean mAllowIo;
+
+    public ServiceThread(String name, int priority, boolean allowIo) {
         super(name, priority);
+        mAllowIo = allowIo;
     }
 
     @Override
@@ -36,7 +39,7 @@
         Process.setCanSelfBackground(false);
 
         // For debug builds, log event loop stalls to dropbox for analysis.
-        if (StrictMode.conditionallyEnableDebugLogging()) {
+        if (!mAllowIo && StrictMode.conditionallyEnableDebugLogging()) {
             Slog.i(TAG, "Enabled StrictMode logging for " + getName() + " looper.");
         }
 
diff --git a/services/core/java/com/android/server/SystemServer.java b/services/core/java/com/android/server/SystemServer.java
index c66a849..6a76388 100644
--- a/services/core/java/com/android/server/SystemServer.java
+++ b/services/core/java/com/android/server/SystemServer.java
@@ -121,8 +121,11 @@
     private Context mSystemContext;
     private SystemServiceManager mSystemServiceManager;
 
-    private Installer mInstaller; // TODO: remove this
-    private PowerManagerService mPowerManagerService; // TODO: remove this
+    // TODO: remove all of these references by improving dependency resolution and boot phases
+    private Installer mInstaller;
+    private PowerManagerService mPowerManagerService;
+    private ActivityManagerService mActivityManagerService;
+    private DisplayManagerService mDisplayManagerService;
     private ContentResolver mContentResolver;
 
     /**
@@ -213,6 +216,7 @@
         // Start services.
         try {
             startBootstrapServices();
+            startCoreServices();
             startOtherServices();
         } catch (RuntimeException ex) {
             Slog.e("System", "******************************************");
@@ -271,22 +275,21 @@
         mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
 
         // Activity manager runs the show.
-        mSystemServiceManager.startService(ActivityManagerService.Lifecycle.class);
+        mActivityManagerService = mSystemServiceManager.startService(
+                ActivityManagerService.Lifecycle.class).getService();
+    }
+
+    private void startCoreServices() {
+        // Display manager is needed to provide display metrics before package manager
+        // starts up.
+        mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
     }
 
     private void startOtherServices() {
-        // Create a handler thread that window manager will use.
-        final ServiceThread windowManagerThread = new ServiceThread("WindowManager",
-                android.os.Process.THREAD_PRIORITY_DISPLAY);
-        windowManagerThread.start();
-        final Handler windowManagerHandler = new Handler(windowManagerThread.getLooper());
-        Watchdog.getInstance().addThread(windowManagerHandler);
-
         final Context context = mSystemContext;
         AccountManagerService accountManager = null;
         ContentService contentService = null;
         LightsManager lights = null;
-        DisplayManagerService display = null;
         BatteryService battery = null;
         VibratorService vibrator = null;
         IAlarmManager alarm = null;
@@ -324,10 +327,6 @@
         boolean disableNetwork = SystemProperties.getBoolean("config.disable_network", false);
 
         try {
-            Slog.i(TAG, "Display Manager");
-            display = new DisplayManagerService(context, windowManagerHandler);
-            ServiceManager.addService(Context.DISPLAY_SERVICE, display, true);
-
             Slog.i(TAG, "Telephony Registry");
             telephonyRegistry = new TelephonyRegistry(context);
             ServiceManager.addService("telephony.registry", telephonyRegistry);
@@ -337,10 +336,8 @@
 
             AttributeCache.init(context);
 
-            if (!display.waitForDefaultDisplay()) {
-                reportWtf("Timeout waiting for default display to be initialized.",
-                        new Throwable());
-            }
+            // We need the default display before we can initialize the package manager.
+            mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
 
             Slog.i(TAG, "Package Manager");
             // Only run "core" apps if we're encrypting the device.
@@ -361,7 +358,7 @@
             } catch (RemoteException e) {
             }
 
-            ActivityManagerService.setSystemProcess();
+            mActivityManagerService.setSystemProcess();
 
             Slog.i(TAG, "Entropy Mixer");
             ServiceManager.addService("entropy", new EntropyMixer(context));
@@ -387,7 +384,7 @@
                     mFactoryTestMode == FactoryTest.FACTORY_TEST_LOW_LEVEL);
 
             Slog.i(TAG, "System Content Providers");
-            ActivityManagerService.installSystemProviders();
+            mActivityManagerService.installSystemProviders();
 
             mSystemServiceManager.startService(LightsService.class);
             lights = LocalServices.getService(LightsManager.class);
@@ -405,7 +402,7 @@
             // lights service, content providers and the battery service.
             mPowerManagerService.init(lights, battery,
                     BatteryStatsService.getService(),
-                    ActivityManagerService.self().getAppOpsService(), display);
+                    mActivityManagerService.getAppOpsService());
 
             Slog.i(TAG, "Consumer IR Service");
             consumerIr = new ConsumerIrService(context);
@@ -417,26 +414,25 @@
 
             Slog.i(TAG, "Init Watchdog");
             final Watchdog watchdog = Watchdog.getInstance();
-            watchdog.init(context, ActivityManagerService.self());
+            watchdog.init(context, mActivityManagerService);
 
             Slog.i(TAG, "Input Manager");
-            inputManager = new InputManagerService(context, windowManagerHandler);
+            inputManager = new InputManagerService(context);
 
             Slog.i(TAG, "Window Manager");
-            wm = WindowManagerService.main(context, display, inputManager,
-                    windowManagerHandler,
+            wm = WindowManagerService.main(context, inputManager,
                     mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
                     !firstBoot, onlyCore);
             ServiceManager.addService(Context.WINDOW_SERVICE, wm);
             ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
 
-            ActivityManagerService.self().setWindowManager(wm);
+            mActivityManagerService.setWindowManager(wm);
 
             inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
             inputManager.start();
 
-            display.setWindowManager(wm);
-            display.setInputManager(inputManager);
+            // TODO: Use service dependencies instead.
+            mDisplayManagerService.windowManagerAndInputReady();
 
             // Skip Bluetooth if we have an emulator kernel
             // TODO: Use a more reliable check to see if this product should
@@ -599,7 +595,7 @@
                 try {
                     Slog.i(TAG, "NetworkPolicy Service");
                     networkPolicy = new NetworkPolicyManagerService(
-                            context, ActivityManagerService.self(),
+                            context, mActivityManagerService,
                             (IPowerManager)ServiceManager.getService(Context.POWER_SERVICE),
                             networkStats, networkManagement);
                     ServiceManager.addService(Context.NETWORK_POLICY_SERVICE, networkPolicy);
@@ -864,7 +860,7 @@
                 try {
                     Slog.i(TAG, "Dreams Service");
                     // Dreams (interactive idle-time views, a/k/a screen savers)
-                    dreamy = new DreamManagerService(context, windowManagerHandler);
+                    dreamy = new DreamManagerService(context);
                     ServiceManager.addService(DreamService.DREAM_SERVICE, dreamy);
                 } catch (Throwable e) {
                     reportWtf("starting DreamManagerService", e);
@@ -910,7 +906,7 @@
         // we are in safe mode.
         final boolean safeMode = wm.detectSafeMode();
         if (safeMode) {
-            ActivityManagerService.self().enterSafeMode();
+            mActivityManagerService.enterSafeMode();
             // Post the safe mode state in the Zygote class
             Zygote.systemInSafeMode = true;
             // Disable the JIT for the system_server process
@@ -948,7 +944,7 @@
         }
 
         if (safeMode) {
-            ActivityManagerService.self().showSafeModeOverlay();
+            mActivityManagerService.showSafeModeOverlay();
         }
 
         // Update the configuration for this context by hand, because we're going
@@ -974,7 +970,8 @@
         }
 
         try {
-            display.systemReady(safeMode, onlyCore);
+            // TODO: use boot phase and communicate these flags some other way
+            mDisplayManagerService.systemReady(safeMode, onlyCore);
         } catch (Throwable e) {
             reportWtf("making Display Manager Service ready", e);
         }
@@ -1009,12 +1006,12 @@
         // where third party code can really run (but before it has actually
         // started launching the initial applications), for us to complete our
         // initialization.
-        ActivityManagerService.self().systemReady(new Runnable() {
+        mActivityManagerService.systemReady(new Runnable() {
             public void run() {
                 Slog.i(TAG, "Making services ready");
 
                 try {
-                    ActivityManagerService.self().startObservingNativeCrashes();
+                    mActivityManagerService.startObservingNativeCrashes();
                 } catch (Throwable e) {
                     reportWtf("observing native crashes", e);
                 }
diff --git a/services/core/java/com/android/server/UiThread.java b/services/core/java/com/android/server/UiThread.java
index 60d73aa..0beb77f 100644
--- a/services/core/java/com/android/server/UiThread.java
+++ b/services/core/java/com/android/server/UiThread.java
@@ -17,21 +17,18 @@
 package com.android.server;
 
 import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.StrictMode;
-import android.util.Slog;
 
 /**
  * Shared singleton thread for showing UI.  This is a foreground thread, and in
  * additional should not have operations that can take more than a few ms scheduled
  * on it to avoid UI jank.
  */
-public final class UiThread extends HandlerThread {
+public final class UiThread extends ServiceThread {
     private static UiThread sInstance;
     private static Handler sHandler;
 
     private UiThread() {
-        super("android.ui", android.os.Process.THREAD_PRIORITY_FOREGROUND);
+        super("android.ui", android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
     }
 
     private static void ensureThreadLocked() {
@@ -39,19 +36,6 @@
             sInstance = new UiThread();
             sInstance.start();
             sHandler = new Handler(sInstance.getLooper());
-            sHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    //Looper.myLooper().setMessageLogging(new LogPrinter(
-                    //        Log.VERBOSE, "WindowManagerPolicy", Log.LOG_ID_SYSTEM));
-                    android.os.Process.setCanSelfBackground(false);
-
-                    // For debug builds, log event loop stalls to dropbox for analysis.
-                    if (StrictMode.conditionallyEnableDebugLogging()) {
-                        Slog.i("UiThread", "Enabled StrictMode logging for UI thread");
-                    }
-                }
-            });
         }
     }
 
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 11dab0b..1ce073a 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -225,6 +225,9 @@
         // And also check IO thread.
         mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(),
                 "i/o thread", DEFAULT_TIMEOUT));
+        // And the display thread.
+        mHandlerCheckers.add(new HandlerChecker(DisplayThread.getHandler(),
+                "display thread", DEFAULT_TIMEOUT));
     }
 
     public void init(Context context, ActivityManagerService activity) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 75ea853..9ea242c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -998,8 +998,7 @@
 
     WindowManagerService mWindowManager;
 
-    static ActivityManagerService sSelf;
-    static ActivityThread sSystemThread;
+    final ActivityThread mSystemThread;
 
     int mCurrentUserId = 0;
     private UserManagerService mUserManager;
@@ -1735,38 +1734,34 @@
         }
     };
 
-    public static void setSystemProcess() {
+    public void setSystemProcess() {
         try {
-            ActivityManagerService m = sSelf;
-
-            ServiceManager.addService(Context.ACTIVITY_SERVICE, m, true);
-            ServiceManager.addService(ProcessStats.SERVICE_NAME, m.mProcessStats);
-            ServiceManager.addService("meminfo", new MemBinder(m));
-            ServiceManager.addService("gfxinfo", new GraphicsBinder(m));
-            ServiceManager.addService("dbinfo", new DbBinder(m));
+            ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
+            ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
+            ServiceManager.addService("meminfo", new MemBinder(this));
+            ServiceManager.addService("gfxinfo", new GraphicsBinder(this));
+            ServiceManager.addService("dbinfo", new DbBinder(this));
             if (MONITOR_CPU_USAGE) {
-                ServiceManager.addService("cpuinfo", new CpuBinder(m));
+                ServiceManager.addService("cpuinfo", new CpuBinder(this));
             }
-            ServiceManager.addService("permission", new PermissionController(m));
+            ServiceManager.addService("permission", new PermissionController(this));
 
-            ApplicationInfo info =
-                sSelf.mContext.getPackageManager().getApplicationInfo(
-                            "android", STOCK_PM_FLAGS);
-            sSystemThread.installSystemApplicationInfo(info);
+            ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
+                    "android", STOCK_PM_FLAGS);
+            mSystemThread.installSystemApplicationInfo(info);
 
-            synchronized (sSelf) {
-                ProcessRecord app = sSelf.newProcessRecordLocked(info,
-                        info.processName, false);
+            synchronized (this) {
+                ProcessRecord app = newProcessRecordLocked(info, info.processName, false);
                 app.persistent = true;
                 app.pid = MY_PID;
                 app.maxAdj = ProcessList.SYSTEM_ADJ;
-                app.makeActive(sSystemThread.getApplicationThread(), sSelf.mProcessStats);
-                sSelf.mProcessNames.put(app.processName, app.uid, app);
-                synchronized (sSelf.mPidsSelfLocked) {
-                    sSelf.mPidsSelfLocked.put(app.pid, app);
+                app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
+                mProcessNames.put(app.processName, app.uid, app);
+                synchronized (mPidsSelfLocked) {
+                    mPidsSelfLocked.put(app.pid, app);
                 }
-                sSelf.updateLruProcessLocked(app, false, null);
-                sSelf.updateOomAdjLocked();
+                updateLruProcessLocked(app, false, null);
+                updateOomAdjLocked();
             }
         } catch (PackageManager.NameNotFoundException e) {
             throw new RuntimeException(
@@ -1780,14 +1775,10 @@
     }
 
     public void startObservingNativeCrashes() {
-        final NativeCrashListener ncl = new NativeCrashListener();
+        final NativeCrashListener ncl = new NativeCrashListener(this);
         ncl.start();
     }
 
-    public static ActivityManagerService self() {
-        return sSelf;
-    }
-
     public IAppOpsService getAppOpsService() {
         return mAppOpsService;
     }
@@ -1888,20 +1879,23 @@
         public void onStart() {
             mService.start();
         }
+
+        public ActivityManagerService getService() {
+            return mService;
+        }
     }
 
     // Note: This method is invoked on the main thread but may need to attach various
     // handlers to other threads.  So take care to be explicit about the looper.
     public ActivityManagerService(Context systemContext) {
-        sSelf = this;
-        sSystemThread = ActivityThread.currentActivityThread();
-
         mContext = systemContext;
         mFactoryTest = FactoryTest.getMode();
+        mSystemThread = ActivityThread.currentActivityThread();
 
         Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
 
-        mHandlerThread = new ServiceThread(TAG, android.os.Process.THREAD_PRIORITY_FOREGROUND);
+        mHandlerThread = new ServiceThread(TAG,
+                android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
         mHandlerThread.start();
         mHandler = new MainHandler(mHandlerThread.getLooper());
 
@@ -2882,7 +2876,7 @@
 
             // See if we should be showing the platform update setup UI.
             Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
-            List<ResolveInfo> ris = sSelf.mContext.getPackageManager()
+            List<ResolveInfo> ris = mContext.getPackageManager()
                     .queryIntentActivities(intent, PackageManager.GET_META_DATA);
 
             // We don't allow third party apps to replace this.
@@ -7974,11 +7968,11 @@
         }
     }
 
-    public static final void installSystemProviders() {
+    public final void installSystemProviders() {
         List<ProviderInfo> providers;
-        synchronized (sSelf) {
-            ProcessRecord app = sSelf.mProcessNames.get("system", Process.SYSTEM_UID);
-            providers = sSelf.generateApplicationProvidersLocked(app);
+        synchronized (this) {
+            ProcessRecord app = mProcessNames.get("system", Process.SYSTEM_UID);
+            providers = generateApplicationProvidersLocked(app);
             if (providers != null) {
                 for (int i=providers.size()-1; i>=0; i--) {
                     ProviderInfo pi = (ProviderInfo)providers.get(i);
@@ -7991,12 +7985,12 @@
             }
         }
         if (providers != null) {
-            sSystemThread.installSystemProviders(providers);
+            mSystemThread.installSystemProviders(providers);
         }
 
-        sSelf.mCoreSettingsObserver = new CoreSettingsObserver(sSelf);
+        mCoreSettingsObserver = new CoreSettingsObserver(this);
 
-        sSelf.mUsageStatsService.monitorPackages();
+        mUsageStatsService.monitorPackages();
     }
 
     /**
@@ -13996,7 +13990,7 @@
                 // boot, where the first config change needs to guarantee
                 // all resources have that config before following boot
                 // code is executed.
-                sSystemThread.applyConfigurationToResources(configCopy);
+                mSystemThread.applyConfigurationToResources(configCopy);
 
                 if (persistent && Settings.System.hasInterestingConfigurationChanges(changes)) {
                     Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
diff --git a/services/core/java/com/android/server/am/NativeCrashListener.java b/services/core/java/com/android/server/am/NativeCrashListener.java
index 2c7f1f1..b12843b 100644
--- a/services/core/java/com/android/server/am/NativeCrashListener.java
+++ b/services/core/java/com/android/server/am/NativeCrashListener.java
@@ -95,8 +95,8 @@
      * Daemon thread that accept()s incoming domain socket connections from debuggerd
      * and processes the crash dump that is passed through.
      */
-    NativeCrashListener() {
-        mAm = ActivityManagerService.self();
+    NativeCrashListener(ActivityManagerService am) {
+        mAm = am;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 4161147..9ec1122 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -17,6 +17,7 @@
 package com.android.server.display;
 
 import android.graphics.Rect;
+import android.hardware.display.DisplayViewport;
 import android.os.IBinder;
 import android.view.Surface;
 import android.view.SurfaceControl;
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index 11aecdd..75f1f53 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -16,6 +16,7 @@
 
 package com.android.server.display;
 
+import android.hardware.display.DisplayViewport;
 import android.util.DisplayMetrics;
 import android.view.Display;
 import android.view.Surface;
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 12ef65a..d5ee838 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -23,12 +23,17 @@
 import android.content.pm.PackageManager;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManagerGlobal;
+import android.hardware.display.DisplayManagerInternal;
+import android.hardware.display.DisplayViewport;
+import android.hardware.display.DisplayManagerInternal.DisplayTransactionListener;
 import android.hardware.display.IDisplayManager;
 import android.hardware.display.IDisplayManagerCallback;
 import android.hardware.display.WifiDisplayStatus;
+import android.hardware.input.InputManagerInternal;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Process;
@@ -42,7 +47,11 @@
 import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.Surface;
+import android.view.WindowManagerInternal;
 
+import com.android.server.DisplayThread;
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
 import com.android.server.UiThread;
 
 import java.io.FileDescriptor;
@@ -94,7 +103,7 @@
  * avoid this by making all potentially reentrant out-calls asynchronous.
  * </p>
  */
-public final class DisplayManagerService extends IDisplayManager.Stub {
+public final class DisplayManagerService extends SystemService {
     private static final String TAG = "DisplayManagerService";
     private static final boolean DEBUG = false;
 
@@ -115,12 +124,12 @@
     private static final int DISPLAY_BLANK_STATE_BLANKED = 1;
     private static final int DISPLAY_BLANK_STATE_UNBLANKED = 2;
 
-    private final Context mContext;
+    private Context mContext;
     private final DisplayManagerHandler mHandler;
     private final Handler mUiHandler;
     private final DisplayAdapterListener mDisplayAdapterListener;
-    private WindowManagerFuncs mWindowManagerFuncs;
-    private InputManagerFuncs mInputManagerFuncs;
+    private WindowManagerInternal mWindowManagerInternal;
+    private InputManagerInternal mInputManagerInternal;
 
     // The synchronization root for the display manager.
     // This lock guards most of the display manager's state.
@@ -199,57 +208,55 @@
     private final DisplayViewport mTempDefaultViewport = new DisplayViewport();
     private final DisplayViewport mTempExternalTouchViewport = new DisplayViewport();
 
-    public DisplayManagerService(Context context, Handler mainHandler) {
-        mContext = context;
-        mHandler = new DisplayManagerHandler(mainHandler.getLooper());
+    public DisplayManagerService() {
+        mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper());
         mUiHandler = UiThread.getHandler();
         mDisplayAdapterListener = new DisplayAdapterListener();
         mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);
-
-        mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER);
     }
 
-    /**
-     * Pauses the boot process to wait for the first display to be initialized.
-     */
-    public boolean waitForDefaultDisplay() {
-        synchronized (mSyncRoot) {
-            long timeout = SystemClock.uptimeMillis() + WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT;
-            while (mLogicalDisplays.get(Display.DEFAULT_DISPLAY) == null) {
-                long delay = timeout - SystemClock.uptimeMillis();
-                if (delay <= 0) {
-                    return false;
-                }
-                if (DEBUG) {
-                    Slog.d(TAG, "waitForDefaultDisplay: waiting, timeout=" + delay);
-                }
-                try {
-                    mSyncRoot.wait(delay);
-                } catch (InterruptedException ex) {
+    @Override
+    public void onCreate(Context context) {
+        mContext = context;
+    }
+
+    @Override
+    public void onStart() {
+        mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER);
+
+        publishBinderService(Context.DISPLAY_SERVICE, new BinderService(),
+                true /*allowIsolated*/);
+        publishLocalService(DisplayManagerInternal.class, new LocalService());
+    }
+
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == PHASE_WAIT_FOR_DEFAULT_DISPLAY) {
+            synchronized (mSyncRoot) {
+                long timeout = SystemClock.uptimeMillis() + WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT;
+                while (mLogicalDisplays.get(Display.DEFAULT_DISPLAY) == null) {
+                    long delay = timeout - SystemClock.uptimeMillis();
+                    if (delay <= 0) {
+                        throw new RuntimeException("Timeout waiting for default display "
+                                + "to be initialized.");
+                    }
+                    if (DEBUG) {
+                        Slog.d(TAG, "waitForDefaultDisplay: waiting, timeout=" + delay);
+                    }
+                    try {
+                        mSyncRoot.wait(delay);
+                    } catch (InterruptedException ex) {
+                    }
                 }
             }
         }
-        return true;
     }
 
-    /**
-     * Called during initialization to associate the display manager with the
-     * window manager.
-     */
-    public void setWindowManager(WindowManagerFuncs windowManagerFuncs) {
+    // TODO: Use dependencies or a boot phase
+    public void windowManagerAndInputReady() {
         synchronized (mSyncRoot) {
-            mWindowManagerFuncs = windowManagerFuncs;
-            scheduleTraversalLocked(false);
-        }
-    }
-
-    /**
-     * Called during initialization to associate the display manager with the
-     * input manager.
-     */
-    public void setInputManager(InputManagerFuncs inputManagerFuncs) {
-        synchronized (mSyncRoot) {
-            mInputManagerFuncs = inputManagerFuncs;
+            mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
+            mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
             scheduleTraversalLocked(false);
         }
     }
@@ -266,50 +273,19 @@
         mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
     }
 
-    /**
-     * Registers a display transaction listener to provide the client a chance to
-     * update its surfaces within the same transaction as any display layout updates.
-     *
-     * @param listener The listener to register.
-     */
-    public void registerDisplayTransactionListener(DisplayTransactionListener listener) {
-        if (listener == null) {
-            throw new IllegalArgumentException("listener must not be null");
-        }
-
+    private void registerDisplayTransactionListenerInternal(
+            DisplayTransactionListener listener) {
         // List is self-synchronized copy-on-write.
         mDisplayTransactionListeners.add(listener);
     }
 
-    /**
-     * Unregisters a display transaction listener to provide the client a chance to
-     * update its surfaces within the same transaction as any display layout updates.
-     *
-     * @param listener The listener to unregister.
-     */
-    public void unregisterDisplayTransactionListener(DisplayTransactionListener listener) {
-        if (listener == null) {
-            throw new IllegalArgumentException("listener must not be null");
-        }
-
+    private void unregisterDisplayTransactionListenerInternal(
+            DisplayTransactionListener listener) {
         // List is self-synchronized copy-on-write.
         mDisplayTransactionListeners.remove(listener);
     }
 
-    /**
-     * Overrides the display information of a particular logical display.
-     * This is used by the window manager to control the size and characteristics
-     * of the default display.  It is expected to apply the requested change
-     * to the display information synchronously so that applications will immediately
-     * observe the new state.
-     *
-     * NOTE: This method must be the only entry point by which the window manager
-     * influences the logical configuration of displays.
-     *
-     * @param displayId The logical display id.
-     * @param info The new data to be stored.
-     */
-    public void setDisplayInfoOverrideFromWindowManager(
+    private void setDisplayInfoOverrideFromWindowManagerInternal(
             int displayId, DisplayInfo info) {
         synchronized (mSyncRoot) {
             LogicalDisplay display = mLogicalDisplays.get(displayId);
@@ -322,11 +298,7 @@
         }
     }
 
-    /**
-     * Called by the window manager to perform traversals while holding a
-     * surface flinger transaction.
-     */
-    public void performTraversalInTransactionFromWindowManager() {
+    private void performTraversalInTransactionFromWindowManagerInternal() {
         synchronized (mSyncRoot) {
             if (!mPendingTraversal) {
                 return;
@@ -342,10 +314,7 @@
         }
     }
 
-    /**
-     * Called by the power manager to blank all displays.
-     */
-    public void blankAllDisplaysFromPowerManager() {
+    private void blankAllDisplaysFromPowerManagerInternal() {
         synchronized (mSyncRoot) {
             if (mAllDisplayBlankStateFromPowerManager != DISPLAY_BLANK_STATE_BLANKED) {
                 mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_BLANKED;
@@ -355,10 +324,7 @@
         }
     }
 
-    /**
-     * Called by the power manager to unblank all displays.
-     */
-    public void unblankAllDisplaysFromPowerManager() {
+    private void unblankAllDisplaysFromPowerManagerInternal() {
         synchronized (mSyncRoot) {
             if (mAllDisplayBlankStateFromPowerManager != DISPLAY_BLANK_STATE_UNBLANKED) {
                 mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_UNBLANKED;
@@ -368,70 +334,40 @@
         }
     }
 
-    /**
-     * Returns information about the specified logical display.
-     *
-     * @param displayId The logical display id.
-     * @return The logical display info, or null if the display does not exist.  The
-     * returned object must be treated as immutable.
-     */
-    @Override // Binder call
-    public DisplayInfo getDisplayInfo(int displayId) {
-        final int callingUid = Binder.getCallingUid();
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mSyncRoot) {
-                LogicalDisplay display = mLogicalDisplays.get(displayId);
-                if (display != null) {
-                    DisplayInfo info = display.getDisplayInfoLocked();
-                    if (info.hasAccess(callingUid)) {
-                        return info;
-                    }
-                }
-                return null;
-            }
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    /**
-     * Returns the list of all display ids.
-     */
-    @Override // Binder call
-    public int[] getDisplayIds() {
-        final int callingUid = Binder.getCallingUid();
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mSyncRoot) {
-                final int count = mLogicalDisplays.size();
-                int[] displayIds = new int[count];
-                int n = 0;
-                for (int i = 0; i < count; i++) {
-                    LogicalDisplay display = mLogicalDisplays.valueAt(i);
-                    DisplayInfo info = display.getDisplayInfoLocked();
-                    if (info.hasAccess(callingUid)) {
-                        displayIds[n++] = mLogicalDisplays.keyAt(i);
-                    }
-                }
-                if (n != count) {
-                    displayIds = Arrays.copyOfRange(displayIds, 0, n);
-                }
-                return displayIds;
-            }
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    @Override // Binder call
-    public void registerCallback(IDisplayManagerCallback callback) {
-        if (callback == null) {
-            throw new IllegalArgumentException("listener must not be null");
-        }
-
+    private DisplayInfo getDisplayInfoInternal(int displayId, int callingUid) {
         synchronized (mSyncRoot) {
-            int callingPid = Binder.getCallingPid();
+            LogicalDisplay display = mLogicalDisplays.get(displayId);
+            if (display != null) {
+                DisplayInfo info = display.getDisplayInfoLocked();
+                if (info.hasAccess(callingUid)) {
+                    return info;
+                }
+            }
+            return null;
+        }
+    }
+
+    private int[] getDisplayIdsInternal(int callingUid) {
+        synchronized (mSyncRoot) {
+            final int count = mLogicalDisplays.size();
+            int[] displayIds = new int[count];
+            int n = 0;
+            for (int i = 0; i < count; i++) {
+                LogicalDisplay display = mLogicalDisplays.valueAt(i);
+                DisplayInfo info = display.getDisplayInfoLocked();
+                if (info.hasAccess(callingUid)) {
+                    displayIds[n++] = mLogicalDisplays.keyAt(i);
+                }
+            }
+            if (n != count) {
+                displayIds = Arrays.copyOfRange(displayIds, 0, n);
+            }
+            return displayIds;
+        }
+    }
+
+    private void registerCallbackInternal(IDisplayManagerCallback callback, int callingPid) {
+        synchronized (mSyncRoot) {
             if (mCallbacks.get(callingPid) != null) {
                 throw new SecurityException("The calling process has already "
                         + "registered an IDisplayManagerCallback.");
@@ -457,24 +393,14 @@
         }
     }
 
-    @Override // Binder call
-    public void startWifiDisplayScan() {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
-                "Permission required to start wifi display scans");
-
-        final int callingPid = Binder.getCallingPid();
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mSyncRoot) {
-                CallbackRecord record = mCallbacks.get(callingPid);
-                if (record == null) {
-                    throw new IllegalStateException("The calling process has not "
-                            + "registered an IDisplayManagerCallback.");
-                }
-                startWifiDisplayScanLocked(record);
+    private void startWifiDisplayScanInternal(int callingPid) {
+        synchronized (mSyncRoot) {
+            CallbackRecord record = mCallbacks.get(callingPid);
+            if (record == null) {
+                throw new IllegalStateException("The calling process has not "
+                        + "registered an IDisplayManagerCallback.");
             }
-        } finally {
-            Binder.restoreCallingIdentity(token);
+            startWifiDisplayScanLocked(record);
         }
     }
 
@@ -489,24 +415,14 @@
         }
     }
 
-    @Override // Binder call
-    public void stopWifiDisplayScan() {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
-                "Permission required to stop wifi display scans");
-
-        final int callingPid = Binder.getCallingPid();
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mSyncRoot) {
-                CallbackRecord record = mCallbacks.get(callingPid);
-                if (record == null) {
-                    throw new IllegalStateException("The calling process has not "
-                            + "registered an IDisplayManagerCallback.");
-                }
-                stopWifiDisplayScanLocked(record);
+    private void stopWifiDisplayScanInternal(int callingPid) {
+        synchronized (mSyncRoot) {
+            CallbackRecord record = mCallbacks.get(callingPid);
+            if (record == null) {
+                throw new IllegalStateException("The calling process has not "
+                        + "registered an IDisplayManagerCallback.");
             }
-        } finally {
-            Binder.restoreCallingIdentity(token);
+            stopWifiDisplayScanLocked(record);
         }
     }
 
@@ -525,244 +441,106 @@
         }
     }
 
-    @Override // Binder call
-    public void connectWifiDisplay(String address) {
-        if (address == null) {
-            throw new IllegalArgumentException("address must not be null");
-        }
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
-                "Permission required to connect to a wifi display");
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mSyncRoot) {
-                if (mWifiDisplayAdapter != null) {
-                    mWifiDisplayAdapter.requestConnectLocked(address);
-                }
+    private void connectWifiDisplayInternal(String address) {
+        synchronized (mSyncRoot) {
+            if (mWifiDisplayAdapter != null) {
+                mWifiDisplayAdapter.requestConnectLocked(address);
             }
-        } finally {
-            Binder.restoreCallingIdentity(token);
         }
     }
 
-    @Override
-    public void pauseWifiDisplay() {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
-                "Permission required to pause a wifi display session");
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mSyncRoot) {
-                if (mWifiDisplayAdapter != null) {
-                    mWifiDisplayAdapter.requestPauseLocked();
-                }
+    private void pauseWifiDisplayInternal() {
+        synchronized (mSyncRoot) {
+            if (mWifiDisplayAdapter != null) {
+                mWifiDisplayAdapter.requestPauseLocked();
             }
-        } finally {
-            Binder.restoreCallingIdentity(token);
         }
     }
 
-    @Override
-    public void resumeWifiDisplay() {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
-                "Permission required to resume a wifi display session");
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mSyncRoot) {
-                if (mWifiDisplayAdapter != null) {
-                    mWifiDisplayAdapter.requestResumeLocked();
-                }
+    private void resumeWifiDisplayInternal() {
+        synchronized (mSyncRoot) {
+            if (mWifiDisplayAdapter != null) {
+                mWifiDisplayAdapter.requestResumeLocked();
             }
-        } finally {
-            Binder.restoreCallingIdentity(token);
         }
     }
 
-    @Override // Binder call
-    public void disconnectWifiDisplay() {
-        // This request does not require special permissions.
-        // Any app can request disconnection from the currently active wifi display.
-        // This exception should no longer be needed once wifi display control moves
-        // to the media router service.
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mSyncRoot) {
-                if (mWifiDisplayAdapter != null) {
-                    mWifiDisplayAdapter.requestDisconnectLocked();
-                }
+    private void disconnectWifiDisplayInternal() {
+        synchronized (mSyncRoot) {
+            if (mWifiDisplayAdapter != null) {
+                mWifiDisplayAdapter.requestDisconnectLocked();
             }
-        } finally {
-            Binder.restoreCallingIdentity(token);
         }
     }
 
-    @Override // Binder call
-    public void renameWifiDisplay(String address, String alias) {
-        if (address == null) {
-            throw new IllegalArgumentException("address must not be null");
-        }
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
-                "Permission required to rename to a wifi display");
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mSyncRoot) {
-                if (mWifiDisplayAdapter != null) {
-                    mWifiDisplayAdapter.requestRenameLocked(address, alias);
-                }
+    private void renameWifiDisplayInternal(String address, String alias) {
+        synchronized (mSyncRoot) {
+            if (mWifiDisplayAdapter != null) {
+                mWifiDisplayAdapter.requestRenameLocked(address, alias);
             }
-        } finally {
-            Binder.restoreCallingIdentity(token);
         }
     }
 
-    @Override // Binder call
-    public void forgetWifiDisplay(String address) {
-        if (address == null) {
-            throw new IllegalArgumentException("address must not be null");
-        }
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
-                "Permission required to forget to a wifi display");
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mSyncRoot) {
-                if (mWifiDisplayAdapter != null) {
-                    mWifiDisplayAdapter.requestForgetLocked(address);
-                }
+    private void forgetWifiDisplayInternal(String address) {
+        synchronized (mSyncRoot) {
+            if (mWifiDisplayAdapter != null) {
+                mWifiDisplayAdapter.requestForgetLocked(address);
             }
-        } finally {
-            Binder.restoreCallingIdentity(token);
         }
     }
 
-    @Override // Binder call
-    public WifiDisplayStatus getWifiDisplayStatus() {
-        // This request does not require special permissions.
-        // Any app can get information about available wifi displays.
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mSyncRoot) {
-                if (mWifiDisplayAdapter != null) {
-                    return mWifiDisplayAdapter.getWifiDisplayStatusLocked();
-                }
-                return new WifiDisplayStatus();
+    private WifiDisplayStatus getWifiDisplayStatusInternal() {
+        synchronized (mSyncRoot) {
+            if (mWifiDisplayAdapter != null) {
+                return mWifiDisplayAdapter.getWifiDisplayStatusLocked();
             }
-        } finally {
-            Binder.restoreCallingIdentity(token);
+            return new WifiDisplayStatus();
         }
     }
 
-    @Override // Binder call
-    public int createVirtualDisplay(IBinder appToken, String packageName,
+    private int createVirtualDisplayInternal(IBinder appToken, int callingUid, String packageName,
             String name, int width, int height, int densityDpi, Surface surface, int flags) {
-        final int callingUid = Binder.getCallingUid();
-        if (!validatePackageName(callingUid, packageName)) {
-            throw new SecurityException("packageName must match the calling uid");
-        }
-        if (appToken == null) {
-            throw new IllegalArgumentException("appToken must not be null");
-        }
-        if (TextUtils.isEmpty(name)) {
-            throw new IllegalArgumentException("name must be non-null and non-empty");
-        }
-        if (width <= 0 || height <= 0 || densityDpi <= 0) {
-            throw new IllegalArgumentException("width, height, and densityDpi must be "
-                    + "greater than 0");
-        }
-        if (surface == null) {
-            throw new IllegalArgumentException("surface must not be null");
-        }
-        if (callingUid != Process.SYSTEM_UID &&
-                (flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) {
-            if (mContext.checkCallingPermission(android.Manifest.permission.CAPTURE_VIDEO_OUTPUT)
-                    != PackageManager.PERMISSION_GRANTED
-                    && mContext.checkCallingPermission(
-                            android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT)
-                            != PackageManager.PERMISSION_GRANTED) {
-                throw new SecurityException("Requires CAPTURE_VIDEO_OUTPUT or "
-                        + "CAPTURE_SECURE_VIDEO_OUTPUT permission to create a "
-                        + "public virtual display.");
+        synchronized (mSyncRoot) {
+            if (mVirtualDisplayAdapter == null) {
+                Slog.w(TAG, "Rejecting request to create private virtual display "
+                        + "because the virtual display adapter is not available.");
+                return -1;
             }
-        }
-        if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE) != 0) {
-            if (mContext.checkCallingPermission(
-                    android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT)
-                    != PackageManager.PERMISSION_GRANTED) {
-                throw new SecurityException("Requires CAPTURE_SECURE_VIDEO_OUTPUT "
-                        + "to create a secure virtual display.");
+
+            DisplayDevice device = mVirtualDisplayAdapter.createVirtualDisplayLocked(
+                    appToken, callingUid, packageName, name, width, height, densityDpi,
+                    surface, flags);
+            if (device == null) {
+                return -1;
             }
-        }
 
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mSyncRoot) {
-                if (mVirtualDisplayAdapter == null) {
-                    Slog.w(TAG, "Rejecting request to create private virtual display "
-                            + "because the virtual display adapter is not available.");
-                    return -1;
-                }
-
-                DisplayDevice device = mVirtualDisplayAdapter.createVirtualDisplayLocked(
-                        appToken, callingUid, packageName, name, width, height, densityDpi,
-                        surface, flags);
-                if (device == null) {
-                    return -1;
-                }
-
-                handleDisplayDeviceAddedLocked(device);
-                LogicalDisplay display = findLogicalDisplayForDeviceLocked(device);
-                if (display != null) {
-                    return display.getDisplayIdLocked();
-                }
-
-                // Something weird happened and the logical display was not created.
-                Slog.w(TAG, "Rejecting request to create virtual display "
-                        + "because the logical display was not created.");
-                mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken);
-                handleDisplayDeviceRemovedLocked(device);
+            handleDisplayDeviceAddedLocked(device);
+            LogicalDisplay display = findLogicalDisplayForDeviceLocked(device);
+            if (display != null) {
+                return display.getDisplayIdLocked();
             }
-        } finally {
-            Binder.restoreCallingIdentity(token);
+
+            // Something weird happened and the logical display was not created.
+            Slog.w(TAG, "Rejecting request to create virtual display "
+                    + "because the logical display was not created.");
+            mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken);
+            handleDisplayDeviceRemovedLocked(device);
         }
         return -1;
     }
 
-    @Override // Binder call
-    public void releaseVirtualDisplay(IBinder appToken) {
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mSyncRoot) {
-                if (mVirtualDisplayAdapter == null) {
-                    return;
-                }
-
-                DisplayDevice device =
-                        mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken);
-                if (device != null) {
-                    handleDisplayDeviceRemovedLocked(device);
-                }
+    private void releaseVirtualDisplayInternal(IBinder appToken) {
+        synchronized (mSyncRoot) {
+            if (mVirtualDisplayAdapter == null) {
+                return;
             }
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
 
-    private boolean validatePackageName(int uid, String packageName) {
-        if (packageName != null) {
-            String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
-            if (packageNames != null) {
-                for (String n : packageNames) {
-                    if (n.equals(packageName)) {
-                        return true;
-                    }
-                }
+            DisplayDevice device =
+                    mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken);
+            if (device != null) {
+                handleDisplayDeviceRemovedLocked(device);
             }
         }
-        return false;
     }
 
     private void registerDefaultDisplayAdapter() {
@@ -986,26 +764,13 @@
         }
 
         // Tell the input system about these new viewports.
-        if (mInputManagerFuncs != null) {
+        if (mInputManagerInternal != null) {
             mHandler.sendEmptyMessage(MSG_UPDATE_VIEWPORT);
         }
     }
 
-    /**
-     * Tells the display manager whether there is interesting unique content on the
-     * specified logical display.  This is used to control automatic mirroring.
-     * <p>
-     * If the display has unique content, then the display manager arranges for it
-     * to be presented on a physical display if appropriate.  Otherwise, the display manager
-     * may choose to make the physical display mirror some other logical display.
-     * </p>
-     *
-     * @param displayId The logical display id to update.
-     * @param hasContent True if the logical display has content.
-     * @param inTraversal True if called from WindowManagerService during a window traversal prior
-     * to call to performTraversalInTransactionFromWindowManager.
-     */
-    public void setDisplayHasContent(int displayId, boolean hasContent, boolean inTraversal) {
+    private void setDisplayHasContentInternal(int displayId, boolean hasContent,
+            boolean inTraversal) {
         synchronized (mSyncRoot) {
             LogicalDisplay display = mLogicalDisplays.get(displayId);
             if (display != null && display.hasContentLocked() != hasContent) {
@@ -1091,7 +856,7 @@
     // Requests that performTraversalsInTransactionFromWindowManager be called at a
     // later time to apply changes to surfaces and displays.
     private void scheduleTraversalLocked(boolean inTraversal) {
-        if (!mPendingTraversal && mWindowManagerFuncs != null) {
+        if (!mPendingTraversal && mWindowManagerInternal != null) {
             mPendingTraversal = true;
             if (!inTraversal) {
                 mHandler.sendEmptyMessage(MSG_REQUEST_TRAVERSAL);
@@ -1124,16 +889,7 @@
         mTempCallbacks.clear();
     }
 
-    @Override // Binder call
-    public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
-        if (mContext == null
-                || mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
-                        != PackageManager.PERMISSION_GRANTED) {
-            pw.println("Permission Denial: can't dump DisplayManager from from pid="
-                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
-            return;
-        }
-
+    private void dumpInternal(PrintWriter pw) {
         pw.println("DISPLAY MANAGER (dumpsys display)");
 
         synchronized (mSyncRoot) {
@@ -1195,30 +951,6 @@
     public static final class SyncRoot {
     }
 
-    /**
-     * Private interface to the window manager.
-     */
-    public interface WindowManagerFuncs {
-        /**
-         * Request that the window manager call
-         * {@link #performTraversalInTransactionFromWindowManager} within a surface
-         * transaction at a later time.
-         */
-        void requestTraversal();
-    }
-
-    /**
-     * Private interface to the input manager.
-     */
-    public interface InputManagerFuncs {
-        /**
-         * Sets information about the displays as needed by the input system.
-         * The input system should copy this information if required.
-         */
-        void setDisplayViewports(DisplayViewport defaultViewport,
-                DisplayViewport externalTouchViewport);
-    }
-
     private final class DisplayManagerHandler extends Handler {
         public DisplayManagerHandler(Looper looper) {
             super(looper, null, true /*async*/);
@@ -1240,7 +972,7 @@
                     break;
 
                 case MSG_REQUEST_TRAVERSAL:
-                    mWindowManagerFuncs.requestTraversal();
+                    mWindowManagerInternal.requestTraversalFromDisplayManager();
                     break;
 
                 case MSG_UPDATE_VIEWPORT: {
@@ -1248,7 +980,7 @@
                         mTempDefaultViewport.copyFrom(mDefaultViewport);
                         mTempExternalTouchViewport.copyFrom(mExternalTouchViewport);
                     }
-                    mInputManagerFuncs.setDisplayViewports(
+                    mInputManagerInternal.setDisplayViewports(
                             mTempDefaultViewport, mTempExternalTouchViewport);
                     break;
                 }
@@ -1311,4 +1043,325 @@
             }
         }
     }
+
+    private final class BinderService extends IDisplayManager.Stub {
+        /**
+         * Returns information about the specified logical display.
+         *
+         * @param displayId The logical display id.
+         * @return The logical display info, or null if the display does not exist.  The
+         * returned object must be treated as immutable.
+         */
+        @Override // Binder call
+        public DisplayInfo getDisplayInfo(int displayId) {
+            final int callingUid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return getDisplayInfoInternal(displayId, callingUid);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        /**
+         * Returns the list of all display ids.
+         */
+        @Override // Binder call
+        public int[] getDisplayIds() {
+            final int callingUid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return getDisplayIdsInternal(callingUid);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
+        public void registerCallback(IDisplayManagerCallback callback) {
+            if (callback == null) {
+                throw new IllegalArgumentException("listener must not be null");
+            }
+
+            final int callingPid = Binder.getCallingPid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                registerCallbackInternal(callback, callingPid);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
+        public void startWifiDisplayScan() {
+            mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+                    "Permission required to start wifi display scans");
+
+            final int callingPid = Binder.getCallingPid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                startWifiDisplayScanInternal(callingPid);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
+        public void stopWifiDisplayScan() {
+            mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+                    "Permission required to stop wifi display scans");
+
+            final int callingPid = Binder.getCallingPid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                stopWifiDisplayScanInternal(callingPid);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
+        public void connectWifiDisplay(String address) {
+            if (address == null) {
+                throw new IllegalArgumentException("address must not be null");
+            }
+            mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+                    "Permission required to connect to a wifi display");
+
+            final long token = Binder.clearCallingIdentity();
+            try {
+                connectWifiDisplayInternal(address);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
+        public void disconnectWifiDisplay() {
+            // This request does not require special permissions.
+            // Any app can request disconnection from the currently active wifi display.
+            // This exception should no longer be needed once wifi display control moves
+            // to the media router service.
+
+            final long token = Binder.clearCallingIdentity();
+            try {
+                disconnectWifiDisplayInternal();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
+        public void renameWifiDisplay(String address, String alias) {
+            if (address == null) {
+                throw new IllegalArgumentException("address must not be null");
+            }
+            mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+                    "Permission required to rename to a wifi display");
+
+            final long token = Binder.clearCallingIdentity();
+            try {
+                renameWifiDisplayInternal(address, alias);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
+        public void forgetWifiDisplay(String address) {
+            if (address == null) {
+                throw new IllegalArgumentException("address must not be null");
+            }
+            mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+                    "Permission required to forget to a wifi display");
+
+            final long token = Binder.clearCallingIdentity();
+            try {
+                forgetWifiDisplayInternal(address);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
+        public void pauseWifiDisplay() {
+            mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+                    "Permission required to pause a wifi display session");
+
+            final long token = Binder.clearCallingIdentity();
+            try {
+                pauseWifiDisplayInternal();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
+        public void resumeWifiDisplay() {
+            mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+                    "Permission required to resume a wifi display session");
+
+            final long token = Binder.clearCallingIdentity();
+            try {
+                resumeWifiDisplayInternal();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
+        public WifiDisplayStatus getWifiDisplayStatus() {
+            // This request does not require special permissions.
+            // Any app can get information about available wifi displays.
+
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return getWifiDisplayStatusInternal();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
+        public int createVirtualDisplay(IBinder appToken, String packageName,
+                String name, int width, int height, int densityDpi, Surface surface, int flags) {
+            final int callingUid = Binder.getCallingUid();
+            if (!validatePackageName(callingUid, packageName)) {
+                throw new SecurityException("packageName must match the calling uid");
+            }
+            if (appToken == null) {
+                throw new IllegalArgumentException("appToken must not be null");
+            }
+            if (TextUtils.isEmpty(name)) {
+                throw new IllegalArgumentException("name must be non-null and non-empty");
+            }
+            if (width <= 0 || height <= 0 || densityDpi <= 0) {
+                throw new IllegalArgumentException("width, height, and densityDpi must be "
+                        + "greater than 0");
+            }
+            if (surface == null) {
+                throw new IllegalArgumentException("surface must not be null");
+            }
+            if (callingUid != Process.SYSTEM_UID &&
+                    (flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) {
+                if (mContext.checkCallingPermission(android.Manifest.permission.CAPTURE_VIDEO_OUTPUT)
+                        != PackageManager.PERMISSION_GRANTED
+                        && mContext.checkCallingPermission(
+                                android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT)
+                                != PackageManager.PERMISSION_GRANTED) {
+                    throw new SecurityException("Requires CAPTURE_VIDEO_OUTPUT or "
+                            + "CAPTURE_SECURE_VIDEO_OUTPUT permission to create a "
+                            + "public virtual display.");
+                }
+            }
+            if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE) != 0) {
+                if (mContext.checkCallingPermission(
+                        android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT)
+                        != PackageManager.PERMISSION_GRANTED) {
+                    throw new SecurityException("Requires CAPTURE_SECURE_VIDEO_OUTPUT "
+                            + "to create a secure virtual display.");
+                }
+            }
+
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return createVirtualDisplayInternal(appToken, callingUid, packageName,
+                        name, width, height, densityDpi, surface, flags);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
+        public void releaseVirtualDisplay(IBinder appToken) {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                releaseVirtualDisplayInternal(appToken);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
+        public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
+            if (mContext == null
+                    || mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
+                            != PackageManager.PERMISSION_GRANTED) {
+                pw.println("Permission Denial: can't dump DisplayManager from from pid="
+                        + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
+                return;
+            }
+
+            final long token = Binder.clearCallingIdentity();
+            try {
+                dumpInternal(pw);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        private boolean validatePackageName(int uid, String packageName) {
+            if (packageName != null) {
+                String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
+                if (packageNames != null) {
+                    for (String n : packageNames) {
+                        if (n.equals(packageName)) {
+                            return true;
+                        }
+                    }
+                }
+            }
+            return false;
+        }
+    }
+
+    private final class LocalService extends DisplayManagerInternal {
+        @Override
+        public void blankAllDisplaysFromPowerManager() {
+            blankAllDisplaysFromPowerManagerInternal();
+        }
+
+        @Override
+        public void unblankAllDisplaysFromPowerManager() {
+            unblankAllDisplaysFromPowerManagerInternal();
+        }
+
+        @Override
+        public DisplayInfo getDisplayInfo(int displayId) {
+            return getDisplayInfoInternal(displayId, Process.myUid());
+        }
+
+        @Override
+        public void registerDisplayTransactionListener(DisplayTransactionListener listener) {
+            if (listener == null) {
+                throw new IllegalArgumentException("listener must not be null");
+            }
+
+            registerDisplayTransactionListenerInternal(listener);
+        }
+
+        @Override
+        public void unregisterDisplayTransactionListener(DisplayTransactionListener listener) {
+            if (listener == null) {
+                throw new IllegalArgumentException("listener must not be null");
+            }
+
+            unregisterDisplayTransactionListenerInternal(listener);
+        }
+
+        @Override
+        public void setDisplayInfoOverrideFromWindowManager(int displayId, DisplayInfo info) {
+            setDisplayInfoOverrideFromWindowManagerInternal(displayId, info);
+        }
+
+        @Override
+        public void performTraversalInTransactionFromWindowManager() {
+            performTraversalInTransactionFromWindowManagerInternal();
+        }
+
+        @Override
+        public void setDisplayHasContent(int displayId, boolean hasContent, boolean inTraversal) {
+            setDisplayHasContentInternal(displayId, hasContent, inTraversal);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/display/DisplayTransactionListener.java b/services/core/java/com/android/server/display/DisplayTransactionListener.java
deleted file mode 100644
index 34eb8f9..0000000
--- a/services/core/java/com/android/server/display/DisplayTransactionListener.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2012 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.display;
-
-/**
- * Called within a Surface transaction whenever the size or orientation of a
- * display may have changed.  Provides an opportunity for the client to
- * update the position of its surfaces as part of the same transaction.
- */
-public interface DisplayTransactionListener {
-    void onDisplayTransaction();
-}
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index b6e7781..f5acc4c 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -17,6 +17,7 @@
 package com.android.server.dreams;
 
 import com.android.internal.util.DumpUtils;
+import com.android.server.FgThread;
 
 import android.app.ActivityManager;
 import android.content.BroadcastReceiver;
@@ -65,9 +66,9 @@
     private int mCurrentDreamUserId;
     private boolean mCurrentDreamIsTest;
 
-    public DreamManagerService(Context context, Handler mainHandler) {
+    public DreamManagerService(Context context) {
         mContext = context;
-        mHandler = new DreamHandler(mainHandler.getLooper());
+        mHandler = new DreamHandler(FgThread.get().getLooper());
         mController = new DreamController(context, mHandler, mControllerListener);
 
         mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 9178664..fa18149 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -18,9 +18,9 @@
 
 import com.android.internal.R;
 import com.android.internal.util.XmlUtils;
+import com.android.server.DisplayThread;
+import com.android.server.LocalServices;
 import com.android.server.Watchdog;
-import com.android.server.display.DisplayManagerService;
-import com.android.server.display.DisplayViewport;
 
 import org.xmlpull.v1.XmlPullParser;
 
@@ -44,9 +44,11 @@
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.database.ContentObserver;
+import android.hardware.display.DisplayViewport;
 import android.hardware.input.IInputDevicesChangedListener;
 import android.hardware.input.IInputManager;
 import android.hardware.input.InputManager;
+import android.hardware.input.InputManagerInternal;
 import android.hardware.input.KeyboardLayout;
 import android.os.Binder;
 import android.os.Bundle;
@@ -94,7 +96,7 @@
  * Wraps the C++ InputManager and provides its callbacks.
  */
 public class InputManagerService extends IInputManager.Stub
-        implements Watchdog.Monitor, DisplayManagerService.InputManagerFuncs {
+        implements Watchdog.Monitor {
     static final String TAG = "InputManager";
     static final boolean DEBUG = false;
 
@@ -241,15 +243,17 @@
     /** Whether to use the dev/input/event or uevent subsystem for the audio jack. */
     final boolean mUseDevInputEventForAudioJack;
 
-    public InputManagerService(Context context, Handler handler) {
+    public InputManagerService(Context context) {
         this.mContext = context;
-        this.mHandler = new InputManagerHandler(handler.getLooper());
+        this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
 
         mUseDevInputEventForAudioJack =
                 context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
         Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
                 + mUseDevInputEventForAudioJack);
         mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
+
+        LocalServices.addService(InputManagerInternal.class, new LocalService());
     }
 
     public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
@@ -329,8 +333,7 @@
         nativeReloadDeviceAliases(mPtr);
     }
 
-    @Override
-    public void setDisplayViewports(DisplayViewport defaultViewport,
+    private void setDisplayViewportsInternal(DisplayViewport defaultViewport,
             DisplayViewport externalTouchViewport) {
         if (defaultViewport.valid) {
             setDisplayViewport(false, defaultViewport);
@@ -1639,4 +1642,12 @@
             onVibratorTokenDied(this);
         }
     }
+
+    private final class LocalService extends InputManagerInternal {
+        @Override
+        public void setDisplayViewports(
+                DisplayViewport defaultViewport, DisplayViewport externalTouchViewport) {
+            setDisplayViewportsInternal(defaultViewport, externalTouchViewport);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index eccc3cf..209a4b4 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1126,7 +1126,8 @@
         synchronized (mInstallLock) {
         // writer
         synchronized (mPackages) {
-            mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND);
+            mHandlerThread = new ServiceThread(TAG,
+                    Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
             mHandlerThread.start();
             mHandler = new PackageHandler(mHandlerThread.getLooper());
             Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
diff --git a/services/core/java/com/android/server/power/DisplayPowerController.java b/services/core/java/com/android/server/power/DisplayPowerController.java
index b8a78e3..f1be504 100644
--- a/services/core/java/com/android/server/power/DisplayPowerController.java
+++ b/services/core/java/com/android/server/power/DisplayPowerController.java
@@ -19,7 +19,6 @@
 import com.android.server.lights.LightsManager;
 import com.android.server.twilight.TwilightListener;
 import com.android.server.twilight.TwilightManager;
-import com.android.server.display.DisplayManagerService;
 import com.android.server.twilight.TwilightState;
 
 import android.animation.Animator;
@@ -185,9 +184,6 @@
     // The twilight service.
     private final TwilightManager mTwilight;
 
-    // The display manager.
-    private final DisplayManagerService mDisplayManager;
-
     // The sensor manager.
     private final SensorManager mSensorManager;
 
@@ -353,7 +349,6 @@
      */
     public DisplayPowerController(Looper looper, Context context, Notifier notifier,
             LightsManager lights, TwilightManager twilight, SensorManager sensorManager,
-            DisplayManagerService displayManager,
             SuspendBlocker displaySuspendBlocker, DisplayBlanker displayBlanker,
             Callbacks callbacks, Handler callbackHandler) {
         mHandler = new DisplayControllerHandler(looper);
@@ -366,7 +361,6 @@
         mLights = lights;
         mTwilight = twilight;
         mSensorManager = sensorManager;
-        mDisplayManager = displayManager;
 
         final Resources resources = context.getResources();
 
@@ -527,8 +521,7 @@
     }
 
     private void initialize() {
-        mPowerState = new DisplayPowerState(
-                new ElectronBeam(mDisplayManager), mDisplayBlanker,
+        mPowerState = new DisplayPowerState(new ElectronBeam(), mDisplayBlanker,
                 mLights.getLight(LightsManager.LIGHT_ID_BACKLIGHT));
 
         mElectronBeamOnAnimator = ObjectAnimator.ofFloat(
diff --git a/services/core/java/com/android/server/power/ElectronBeam.java b/services/core/java/com/android/server/power/ElectronBeam.java
index 729bd16..64921d7 100644
--- a/services/core/java/com/android/server/power/ElectronBeam.java
+++ b/services/core/java/com/android/server/power/ElectronBeam.java
@@ -23,6 +23,8 @@
 
 import android.graphics.PixelFormat;
 import android.graphics.SurfaceTexture;
+import android.hardware.display.DisplayManagerInternal;
+import android.hardware.display.DisplayManagerInternal.DisplayTransactionListener;
 import android.opengl.EGL14;
 import android.opengl.EGLConfig;
 import android.opengl.EGLContext;
@@ -40,8 +42,7 @@
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 
-import com.android.server.display.DisplayManagerService;
-import com.android.server.display.DisplayTransactionListener;
+import com.android.server.LocalServices;
 
 /**
  * Bzzzoooop!  *crackle*
@@ -77,7 +78,7 @@
     private boolean mPrepared;
     private int mMode;
 
-    private final DisplayManagerService mDisplayManager;
+    private final DisplayManagerInternal mDisplayManagerInternal;
     private int mDisplayLayerStack; // layer stack associated with primary display
     private int mDisplayWidth;      // real width, not rotated
     private int mDisplayHeight;     // real height, not rotated
@@ -118,8 +119,8 @@
     public static final int MODE_FADE = 2;
 
 
-    public ElectronBeam(DisplayManagerService displayManager) {
-        mDisplayManager = displayManager;
+    public ElectronBeam() {
+        mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
     }
 
     /**
@@ -138,7 +139,7 @@
 
         // Get the display size and layer stack.
         // This is not expected to change while the electron beam surface is showing.
-        DisplayInfo displayInfo = mDisplayManager.getDisplayInfo(Display.DEFAULT_DISPLAY);
+        DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(Display.DEFAULT_DISPLAY);
         mDisplayLayerStack = displayInfo.layerStack;
         mDisplayWidth = displayInfo.getNaturalWidth();
         mDisplayHeight = displayInfo.getNaturalHeight();
@@ -527,7 +528,7 @@
             mSurface = new Surface();
             mSurface.copyFrom(mSurfaceControl);
 
-            mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManager, mSurfaceControl);
+            mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal, mSurfaceControl);
             mSurfaceLayout.onDisplayTransaction();
         } finally {
             SurfaceControl.closeTransaction();
@@ -685,20 +686,21 @@
      * owns the electron beam.
      */
     private static final class NaturalSurfaceLayout implements DisplayTransactionListener {
-        private final DisplayManagerService mDisplayManager;
+        private final DisplayManagerInternal mDisplayManagerInternal;
         private SurfaceControl mSurfaceControl;
 
-        public NaturalSurfaceLayout(DisplayManagerService displayManager, SurfaceControl surfaceControl) {
-            mDisplayManager = displayManager;
+        public NaturalSurfaceLayout(DisplayManagerInternal displayManagerInternal,
+                SurfaceControl surfaceControl) {
+            mDisplayManagerInternal = displayManagerInternal;
             mSurfaceControl = surfaceControl;
-            mDisplayManager.registerDisplayTransactionListener(this);
+            mDisplayManagerInternal.registerDisplayTransactionListener(this);
         }
 
         public void dispose() {
             synchronized (this) {
                 mSurfaceControl = null;
             }
-            mDisplayManager.unregisterDisplayTransactionListener(this);
+            mDisplayManagerInternal.unregisterDisplayTransactionListener(this);
         }
 
         @Override
@@ -708,7 +710,8 @@
                     return;
                 }
 
-                DisplayInfo displayInfo = mDisplayManager.getDisplayInfo(Display.DEFAULT_DISPLAY);
+                DisplayInfo displayInfo =
+                        mDisplayManagerInternal.getDisplayInfo(Display.DEFAULT_DISPLAY);
                 switch (displayInfo.rotation) {
                     case Surface.ROTATION_0:
                         mSurfaceControl.setPosition(0, 0);
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 7f03cc0..94876bb 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -21,12 +21,10 @@
 import com.android.server.BatteryService;
 import com.android.server.EventLogTags;
 import com.android.server.ServiceThread;
-import com.android.server.lights.LightsService;
 import com.android.server.lights.Light;
 import com.android.server.lights.LightsManager;
 import com.android.server.twilight.TwilightManager;
 import com.android.server.Watchdog;
-import com.android.server.display.DisplayManagerService;
 import com.android.server.dreams.DreamManagerService;
 
 import android.Manifest;
@@ -40,11 +38,11 @@
 import android.database.ContentObserver;
 import android.hardware.SensorManager;
 import android.hardware.SystemSensorManager;
+import android.hardware.display.DisplayManagerInternal;
 import android.net.Uri;
 import android.os.BatteryManager;
 import android.os.Binder;
 import android.os.Handler;
-import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.IPowerManager;
 import android.os.Looper;
@@ -173,7 +171,7 @@
     private Context mContext;
     private LightsManager mLightsManager;
     private BatteryService mBatteryService;
-    private DisplayManagerService mDisplayManagerService;
+    private DisplayManagerInternal mDisplayManagerInternal;
     private IBatteryStats mBatteryStats;
     private IAppOpsService mAppOps;
     private ServiceThread mHandlerThread;
@@ -409,13 +407,14 @@
      */
     public void init(LightsManager ls,
             BatteryService bs, IBatteryStats bss,
-            IAppOpsService appOps, DisplayManagerService dm) {
+            IAppOpsService appOps) {
         mLightsManager = ls;
         mBatteryService = bs;
         mBatteryStats = bss;
         mAppOps = appOps;
-        mDisplayManagerService = dm;
-        mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_DISPLAY);
+        mDisplayManagerInternal = getLocalService(DisplayManagerInternal.class);
+        mHandlerThread = new ServiceThread(TAG,
+                Process.THREAD_PRIORITY_DISPLAY, false /*allowIo*/);
         mHandlerThread.start();
         mHandler = new PowerManagerHandler(mHandlerThread.getLooper());
 
@@ -459,7 +458,7 @@
             // own handler thread to ensure timely operation.
             mDisplayPowerController = new DisplayPowerController(mHandler.getLooper(),
                     mContext, mNotifier, mLightsManager, twilight, sensorManager,
-                    mDisplayManagerService, mDisplaySuspendBlocker, mDisplayBlanker,
+                    mDisplaySuspendBlocker, mDisplayBlanker,
                     mDisplayPowerControllerCallbacks, mHandler);
 
             mWirelessChargerDetector = new WirelessChargerDetector(sensorManager,
@@ -2296,7 +2295,7 @@
         public void blankAllDisplays() {
             synchronized (this) {
                 mBlanked = true;
-                mDisplayManagerService.blankAllDisplaysFromPowerManager();
+                mDisplayManagerInternal.blankAllDisplaysFromPowerManager();
                 nativeSetInteractive(false);
                 nativeSetAutoSuspend(true);
             }
@@ -2307,7 +2306,7 @@
             synchronized (this) {
                 nativeSetAutoSuspend(false);
                 nativeSetInteractive(true);
-                mDisplayManagerService.unblankAllDisplaysFromPowerManager();
+                mDisplayManagerInternal.unblankAllDisplaysFromPowerManager();
                 mBlanked = false;
             }
         }
@@ -2694,7 +2693,7 @@
         }
     }
 
-    private final class LocalService implements PowerManagerInternal {
+    private final class LocalService extends PowerManagerInternal {
         /**
          * Used by the window manager to override the screen brightness based on the
          * current foreground activity.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index f77f183..59134f9 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -33,15 +33,13 @@
 import com.android.internal.view.IInputMethodManager;
 import com.android.internal.view.WindowManagerPolicyThread;
 import com.android.server.AttributeCache;
+import com.android.server.DisplayThread;
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
-import com.android.server.SystemService;
 import com.android.server.UiThread;
 import com.android.server.Watchdog;
 import com.android.server.am.BatteryStatsService;
-import com.android.server.display.DisplayManagerService;
 import com.android.server.input.InputManagerService;
-import com.android.server.power.PowerManagerService;
 import com.android.server.power.ShutdownThread;
 
 import android.Manifest;
@@ -68,6 +66,7 @@
 import android.graphics.RectF;
 import android.graphics.Region;
 import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerInternal;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Debug;
@@ -117,6 +116,7 @@
 import android.view.KeyEvent;
 import android.view.MagnificationSpec;
 import android.view.MotionEvent;
+import android.view.WindowManagerInternal;
 import android.view.Surface.OutOfResourcesException;
 import android.view.Surface;
 import android.view.SurfaceControl;
@@ -156,7 +156,7 @@
 /** {@hide} */
 public class WindowManagerService extends IWindowManager.Stub
         implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs,
-                DisplayManagerService.WindowManagerFuncs, DisplayManager.DisplayListener {
+        DisplayManager.DisplayListener {
     static final String TAG = "WindowManager";
     static final boolean DEBUG = false;
     static final boolean DEBUG_ADD_REMOVE = false;
@@ -540,7 +540,7 @@
     float mAnimatorDurationScale = 1.0f;
 
     final InputManagerService mInputManager;
-    final DisplayManagerService mDisplayManagerService;
+    final DisplayManagerInternal mDisplayManagerInternal;
     final DisplayManager mDisplayManager;
 
     // Who is holding the screen on.
@@ -693,23 +693,22 @@
     final boolean mOnlyCore;
 
     public static WindowManagerService main(final Context context,
-            final DisplayManagerService dm,
-            final InputManagerService im, final Handler wmHandler,
+            final InputManagerService im,
             final boolean haveInputMethods, final boolean showBootMsgs,
             final boolean onlyCore) {
         final WindowManagerService[] holder = new WindowManagerService[1];
-        wmHandler.runWithScissors(new Runnable() {
+        DisplayThread.getHandler().runWithScissors(new Runnable() {
             @Override
             public void run() {
-                holder[0] = new WindowManagerService(context, dm, im,
+                holder[0] = new WindowManagerService(context, im,
                         haveInputMethods, showBootMsgs, onlyCore);
             }
         }, 0);
         return holder[0];
     }
 
-    private void initPolicy(Handler uiHandler) {
-        uiHandler.runWithScissors(new Runnable() {
+    private void initPolicy() {
+        UiThread.getHandler().runWithScissors(new Runnable() {
             @Override
             public void run() {
                 WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper());
@@ -722,8 +721,7 @@
         }, 0);
     }
 
-    private WindowManagerService(Context context,
-            DisplayManagerService displayManager, InputManagerService inputManager,
+    private WindowManagerService(Context context, InputManagerService inputManager,
             boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) {
         mContext = context;
         mHaveInputMethods = haveInputMethods;
@@ -732,7 +730,7 @@
         mLimitedAlphaCompositing = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_sf_limitedAlpha);
         mInputManager = inputManager; // Must be before createDisplayContentLocked.
-        mDisplayManagerService = displayManager;
+        mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
         mDisplaySettings = new DisplaySettings(context);
         mDisplaySettings.readSettingsLocked();
 
@@ -788,7 +786,7 @@
 
         mAnimator = new WindowAnimator(this);
 
-        initPolicy(UiThread.getHandler());
+        initPolicy();
 
         // Add ourself to the Watchdog monitors.
         Watchdog.getInstance().addMonitor(this);
@@ -801,6 +799,8 @@
         } finally {
             SurfaceControl.closeTransaction();
         }
+
+        LocalServices.addService(WindowManagerInternal.class, new LocalService());
     }
 
     public InputMonitor getInputMonitor() {
@@ -5919,7 +5919,7 @@
                 }
             }
 
-            mDisplayManagerService.performTraversalInTransactionFromWindowManager();
+            mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
         } finally {
             if (!inTransaction) {
                 SurfaceControl.closeTransaction();
@@ -6613,7 +6613,7 @@
             displayInfo.getLogicalMetrics(mRealDisplayMetrics,
                     CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
             displayInfo.getAppMetrics(mDisplayMetrics);
-            mDisplayManagerService.setDisplayInfoOverrideFromWindowManager(
+            mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(
                     displayContent.getDisplayId(), displayInfo);
         }
         if (false) {
@@ -6946,7 +6946,7 @@
                 synchronized(displayContent.mDisplaySizeLock) {
                     // Bootstrap the default logical display from the display manager.
                     final DisplayInfo displayInfo = displayContent.getDisplayInfo();
-                    DisplayInfo newDisplayInfo = mDisplayManagerService.getDisplayInfo(displayId);
+                    DisplayInfo newDisplayInfo = mDisplayManagerInternal.getDisplayInfo(displayId);
                     if (newDisplayInfo != null) {
                         displayInfo.copyFrom(newDisplayInfo);
                     }
@@ -9108,7 +9108,7 @@
                     updateResizingWindows(w);
                 }
 
-                mDisplayManagerService.setDisplayHasContent(displayId,
+                mDisplayManagerInternal.setDisplayHasContent(displayId,
                         mInnerFields.mDisplayHasContent,
                         true /* inTraversal, must call performTraversalInTrans... below */);
 
@@ -9125,7 +9125,7 @@
 
             // Give the display manager a chance to adjust properties
             // like display rotation if it needs to.
-            mDisplayManagerService.performTraversalInTransactionFromWindowManager();
+            mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
 
         } catch (RuntimeException e) {
             Log.wtf(TAG, "Unhandled exception in Window Manager", e);
@@ -9494,8 +9494,7 @@
         }
     }
 
-    @Override
-    public void requestTraversal() {
+    void requestTraversal() {
         synchronized (mWindowMap) {
             requestTraversalLocked();
         }
@@ -10692,7 +10691,7 @@
             displayInfo.overscanTop = rect.top;
             displayInfo.overscanRight = rect.right;
             displayInfo.overscanBottom = rect.bottom;
-            mDisplayManagerService.setDisplayInfoOverrideFromWindowManager(
+            mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(
                     displayId, displayInfo);
         }
         configureDisplayPolicyLocked(displayContent);
@@ -10815,4 +10814,11 @@
     public Object getWindowManagerLock() {
         return mWindowMap;
     }
+
+    private final class LocalService extends WindowManagerInternal {
+        @Override
+        public void requestTraversalFromDisplayManager() {
+            requestTraversal();
+        }
+    }
 }