am 91ecb36d: ActivityManagerService use lmkd low memory killer daemon -- DO NOT MERGE

* commit '91ecb36df50be3446809e9da2a8f571d157f7549':
  ActivityManagerService use lmkd low memory killer daemon -- DO NOT MERGE
diff --git a/Android.mk b/Android.mk
index 3a3169c..ade5e38 100644
--- a/Android.mk
+++ b/Android.mk
@@ -59,6 +59,8 @@
 	core/java/android/accounts/IAccountManagerResponse.aidl \
 	core/java/android/accounts/IAccountAuthenticator.aidl \
 	core/java/android/accounts/IAccountAuthenticatorResponse.aidl \
+	core/java/android/app/IActivityContainer.aidl \
+	core/java/android/app/IActivityContainerCallback.aidl \
 	core/java/android/app/IActivityController.aidl \
 	core/java/android/app/IActivityPendingResult.aidl \
 	core/java/android/app/IAlarmManager.aidl \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index cfa8be9..ef3f4ae 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -184,7 +184,7 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/media/audio/effects/)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/framework-res_intermediates)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/print/IPrintClient.*)
-
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/services_intermediates)
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
 # ************************************************
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 0344d26..7adf5ec 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -19,8 +19,9 @@
 package com.android.commands.am;
 
 import android.app.ActivityManager;
-import android.app.ActivityManager.StackBoxInfo;
+import android.app.ActivityManager.StackInfo;
 import android.app.ActivityManagerNative;
+import android.app.IActivityContainer;
 import android.app.IActivityController;
 import android.app.IActivityManager;
 import android.app.IInstrumentationWatcher;
@@ -31,9 +32,11 @@
 import android.content.Intent;
 import android.content.pm.IPackageManager;
 import android.content.pm.ResolveInfo;
+import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -106,11 +109,11 @@
                 "       am to-intent-uri [INTENT]\n" +
                 "       am switch-user <USER_ID>\n" +
                 "       am stop-user <USER_ID>\n" +
-                "       am stack create <TASK_ID> <RELATIVE_STACK_BOX_ID> <POSITION> <WEIGHT>\n" +
+                "       am stack create <TASK_ID> <DISPLAY_ID>\n" +
                 "       am stack movetask <TASK_ID> <STACK_ID> [true|false]\n" +
-                "       am stack resize <STACK_ID> <WEIGHT>\n" +
-                "       am stack boxes\n" +
-                "       am stack box <STACK_BOX_ID>\n" +
+                "       am stack resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
+                "       am stack list\n" +
+                "       am stack info <STACK_ID>\n" +
                 "\n" +
                 "am start: start an Activity.  Options are:\n" +
                 "    -D: enable debugging\n" +
@@ -204,24 +207,16 @@
                 "am stop-user: stop execution of USER_ID, not allowing it to run any\n" +
                 "  code until a later explicit switch to it.\n" +
                 "\n" +
-                "am stack create: create a new stack relative to an existing one.\n" +
-                "   <TASK_ID>: the task to populate the new stack with. Must exist.\n" +
-                "   <RELATIVE_STACK_BOX_ID>: existing stack box's id.\n" +
-                "   <POSITION>: 0: before <RELATIVE_STACK_BOX_ID>, per RTL/LTR configuration,\n" +
-                "               1: after <RELATIVE_STACK_BOX_ID>, per RTL/LTR configuration,\n" +
-                "               2: to left of <RELATIVE_STACK_BOX_ID>,\n" +
-                "               3: to right of <RELATIVE_STACK_BOX_ID>," +
-                "               4: above <RELATIVE_STACK_BOX_ID>, 5: below <RELATIVE_STACK_BOX_ID>\n" +
-                "   <WEIGHT>: float between 0.2 and 0.8 inclusive.\n" +
+                "am stack create: create a new stack containing <TASK_ID> which must exist\n" +
                 "\n" +
                 "am stack movetask: move <TASK_ID> from its current stack to the top (true) or" +
                 "   bottom (false) of <STACK_ID>.\n" +
                 "\n" +
-                "am stack resize: change <STACK_ID> relative size to new <WEIGHT>.\n" +
+                "am stack resize: change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>.\n" +
                 "\n" +
-                "am stack boxes: list the hierarchy of stack boxes and their contents.\n" +
+                "am stack list: list all of the activity stacks and their sizes.\n" +
                 "\n" +
-                "am stack box: list the hierarchy of stack boxes rooted at <STACK_BOX_ID>.\n" +
+                "am stack info: display the information about activity stack <STACK_ID>.\n" +
                 "\n" +
                 "<INTENT> specifications include these flags and arguments:\n" +
                 "    [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" +
@@ -1551,11 +1546,11 @@
         } else if (op.equals("movetask")) {
             runStackMoveTask();
         } else if (op.equals("resize")) {
-            runStackBoxResize();
-        } else if (op.equals("boxes")) {
-            runStackBoxes();
-        } else if (op.equals("box")) {
-            runStackBoxInfo();
+            runStackResize();
+        } else if (op.equals("list")) {
+            runStackList();
+        } else if (op.equals("info")) {
+            runStackInfo();
         } else {
             showError("Error: unknown command '" + op + "'");
             return;
@@ -1565,16 +1560,16 @@
     private void runStackCreate() throws Exception {
         String taskIdStr = nextArgRequired();
         int taskId = Integer.valueOf(taskIdStr);
-        String relativeToStr = nextArgRequired();
-        int relativeTo = Integer.valueOf(relativeToStr);
-        String positionStr = nextArgRequired();
-        int position = Integer.valueOf(positionStr);
-        String weightStr = nextArgRequired();
-        float weight = Float.valueOf(weightStr);
+        String displayIdStr = nextArgRequired();
+        int displayId = Integer.valueOf(displayIdStr);
 
         try {
-            int stackId = mAm.createStack(taskId, relativeTo, position, weight);
-            System.out.println("createStack returned new stackId=" + stackId + "\n\n");
+            IBinder homeActivityToken = mAm.getHomeActivityToken();
+            IActivityContainer container = mAm.createActivityContainer(homeActivityToken, null);
+            final int stackId = container.getStackId();
+            System.out.println("createStack returned new stackId=" + stackId + "\n");
+            container.attachToDisplay(displayId);
+            mAm.moveTaskToStack(taskId, stackId, true);
         } catch (RemoteException e) {
         }
     }
@@ -1601,34 +1596,40 @@
         }
     }
 
-    private void runStackBoxResize() throws Exception {
-        String stackBoxIdStr = nextArgRequired();
-        int stackBoxId = Integer.valueOf(stackBoxIdStr);
-        String weightStr = nextArgRequired();
-        float weight = Float.valueOf(weightStr);
+    private void runStackResize() throws Exception {
+        String stackIdStr = nextArgRequired();
+        int stackId = Integer.valueOf(stackIdStr);
+        String leftStr = nextArgRequired();
+        int left = Integer.valueOf(leftStr);
+        String topStr = nextArgRequired();
+        int top = Integer.valueOf(topStr);
+        String rightStr = nextArgRequired();
+        int right = Integer.valueOf(rightStr);
+        String bottomStr = nextArgRequired();
+        int bottom = Integer.valueOf(bottomStr);
 
         try {
-            mAm.resizeStackBox(stackBoxId, weight);
+            mAm.resizeStack(stackId, new Rect(left, top, right, bottom));
         } catch (RemoteException e) {
         }
     }
 
-    private void runStackBoxes() throws Exception {
+    private void runStackList() throws Exception {
         try {
-            List<StackBoxInfo> stackBoxes = mAm.getStackBoxes();
-            for (StackBoxInfo info : stackBoxes) {
+            List<StackInfo> stacks = mAm.getAllStackInfos();
+            for (StackInfo info : stacks) {
                 System.out.println(info);
             }
         } catch (RemoteException e) {
         }
     }
 
-    private void runStackBoxInfo() throws Exception {
+    private void runStackInfo() throws Exception {
         try {
-            String stackBoxIdStr = nextArgRequired();
-            int stackBoxId = Integer.valueOf(stackBoxIdStr);
-            StackBoxInfo stackBoxInfo = mAm.getStackBoxInfo(stackBoxId); 
-            System.out.println(stackBoxInfo);
+            String stackIdStr = nextArgRequired();
+            int stackId = Integer.valueOf(stackIdStr);
+            StackInfo info = mAm.getStackInfo(stackId);
+            System.out.println(info);
         } catch (RemoteException e) {
         }
     }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 7ca3459..c877cd3 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1289,106 +1289,15 @@
     }
 
     /**
-     * Information you can retrieve about the WindowManager StackBox hierarchy.
-     * @hide
-     */
-    public static class StackBoxInfo implements Parcelable {
-        public int stackBoxId;
-        public float weight;
-        public boolean vertical;
-        public Rect bounds;
-        public StackBoxInfo[] children;
-        public int stackId;
-        public StackInfo stack;
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(stackBoxId);
-            dest.writeFloat(weight);
-            dest.writeInt(vertical ? 1 : 0);
-            bounds.writeToParcel(dest, flags);
-            dest.writeInt(stackId);
-            if (children != null) {
-                children[0].writeToParcel(dest, flags);
-                children[1].writeToParcel(dest, flags);
-            } else {
-                stack.writeToParcel(dest, flags);
-            }
-        }
-
-        public void readFromParcel(Parcel source) {
-            stackBoxId = source.readInt();
-            weight = source.readFloat();
-            vertical = source.readInt() == 1;
-            bounds = Rect.CREATOR.createFromParcel(source);
-            stackId = source.readInt();
-            if (stackId == -1) {
-                children = new StackBoxInfo[2];
-                children[0] = StackBoxInfo.CREATOR.createFromParcel(source);
-                children[1] = StackBoxInfo.CREATOR.createFromParcel(source);
-            } else {
-                stack = StackInfo.CREATOR.createFromParcel(source);
-            }
-        }
-
-        public static final Creator<StackBoxInfo> CREATOR =
-                new Creator<ActivityManager.StackBoxInfo>() {
-
-            @Override
-            public StackBoxInfo createFromParcel(Parcel source) {
-                return new StackBoxInfo(source);
-            }
-
-            @Override
-            public StackBoxInfo[] newArray(int size) {
-                return new StackBoxInfo[size];
-            }
-        };
-
-        public StackBoxInfo() {
-        }
-
-        public StackBoxInfo(Parcel source) {
-            readFromParcel(source);
-        }
-
-        public String toString(String prefix) {
-            StringBuilder sb = new StringBuilder(256);
-            sb.append(prefix); sb.append("Box id=" + stackBoxId); sb.append(" weight=" + weight);
-            sb.append(" vertical=" + vertical); sb.append(" bounds=" + bounds.toShortString());
-            sb.append("\n");
-            if (children != null) {
-                sb.append(prefix); sb.append("First child=\n");
-                sb.append(children[0].toString(prefix + "  "));
-                sb.append(prefix); sb.append("Second child=\n");
-                sb.append(children[1].toString(prefix + "  "));
-            } else {
-                sb.append(prefix); sb.append("Stack=\n");
-                sb.append(stack.toString(prefix + "  "));
-            }
-            return sb.toString();
-        }
-
-        @Override
-        public String toString() {
-            return toString("");
-        }
-    }
-
-    /**
      * Information you can retrieve about an ActivityStack in the system.
      * @hide
      */
     public static class StackInfo implements Parcelable {
         public int stackId;
-        public Rect bounds;
+        public Rect bounds = new Rect();
         public int[] taskIds;
         public String[] taskNames;
+        public int displayId;
 
         @Override
         public int describeContents() {
@@ -1404,6 +1313,7 @@
             dest.writeInt(bounds.bottom);
             dest.writeIntArray(taskIds);
             dest.writeStringArray(taskNames);
+            dest.writeInt(displayId);
         }
 
         public void readFromParcel(Parcel source) {
@@ -1412,6 +1322,7 @@
                     source.readInt(), source.readInt(), source.readInt(), source.readInt());
             taskIds = source.createIntArray();
             taskNames = source.createStringArray();
+            displayId = source.readInt();
         }
 
         public static final Creator<StackInfo> CREATOR = new Creator<StackInfo>() {
@@ -1435,7 +1346,9 @@
         public String toString(String prefix) {
             StringBuilder sb = new StringBuilder(256);
             sb.append(prefix); sb.append("Stack id="); sb.append(stackId);
-                    sb.append(" bounds="); sb.append(bounds.toShortString()); sb.append("\n");
+                    sb.append(" bounds="); sb.append(bounds.toShortString());
+                    sb.append(" displayId="); sb.append(displayId);
+                    sb.append("\n");
             prefix = prefix + "  ";
             for (int i = 0; i < taskIds.length; ++i) {
                 sb.append(prefix); sb.append("taskId="); sb.append(taskIds[i]);
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 74266cc..0f38095 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -16,7 +16,7 @@
 
 package android.app;
 
-import android.app.ActivityManager.StackBoxInfo;
+import android.app.ActivityManager.StackInfo;
 import android.content.ComponentName;
 import android.content.IIntentReceiver;
 import android.content.IIntentSender;
@@ -31,6 +31,7 @@
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
+import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
@@ -611,18 +612,6 @@
             return true;
         }
 
-        case CREATE_STACK_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int taskId = data.readInt();
-            int relativeStackId = data.readInt();
-            int position = data.readInt();
-            float weight = data.readFloat();
-            int res = createStack(taskId, relativeStackId, position, weight);
-            reply.writeNoException();
-            reply.writeInt(res);
-            return true;
-        }
-
         case MOVE_TASK_TO_STACK_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             int taskId = data.readInt();
@@ -635,25 +624,26 @@
 
         case RESIZE_STACK_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
-            int stackBoxId = data.readInt();
+            int stackId = data.readInt();
             float weight = data.readFloat();
-            resizeStackBox(stackBoxId, weight);
+            Rect r = Rect.CREATOR.createFromParcel(data);
+            resizeStack(stackId, r);
             reply.writeNoException();
             return true;
         }
 
-        case GET_STACK_BOXES_TRANSACTION: {
+        case GET_ALL_STACK_INFOS_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
-            List<StackBoxInfo> list = getStackBoxes();
+            List<StackInfo> list = getAllStackInfos();
             reply.writeNoException();
             reply.writeTypedList(list);
             return true;
         }
 
-        case GET_STACK_BOX_INFO_TRANSACTION: {
+        case GET_STACK_INFO_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
-            int stackBoxId = data.readInt();
-            StackBoxInfo info = getStackBoxInfo(stackBoxId);
+            int stackId = data.readInt();
+            StackInfo info = getStackInfo(stackId);
             reply.writeNoException();
             if (info != null) {
                 reply.writeInt(1);
@@ -2028,6 +2018,26 @@
             reply.writeNoException();
             return true;
         }
+
+        case CREATE_ACTIVITY_CONTAINER_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder parentActivityToken = data.readStrongBinder();
+            IActivityContainerCallback callback =
+                    (IActivityContainerCallback) data.readStrongBinder();
+            IActivityContainer activityContainer =
+                    createActivityContainer(parentActivityToken, callback);
+            reply.writeNoException();
+            reply.writeStrongBinder(activityContainer.asBinder());
+            return true;
+        }
+
+        case GET_HOME_ACTIVITY_TOKEN_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder homeActivityToken = getHomeActivityToken();
+            reply.writeNoException();
+            reply.writeStrongBinder(homeActivityToken);
+            return true;
+        }
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -2715,24 +2725,6 @@
         reply.recycle();
     }
     @Override
-    public int createStack(int taskId, int relativeStackBoxId, int position, float weight)
-            throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(taskId);
-        data.writeInt(relativeStackBoxId);
-        data.writeInt(position);
-        data.writeFloat(weight);
-        mRemote.transact(CREATE_STACK_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int res = reply.readInt();
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-    @Override
     public void moveTaskToStack(int taskId, int stackId, boolean toTop) throws RemoteException
     {
         Parcel data = Parcel.obtain();
@@ -2747,44 +2739,44 @@
         reply.recycle();
     }
     @Override
-    public void resizeStackBox(int stackBoxId, float weight) throws RemoteException
+    public void resizeStack(int stackBoxId, Rect r) throws RemoteException
     {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeInt(stackBoxId);
-        data.writeFloat(weight);
+        r.writeToParcel(data, 0);
         mRemote.transact(RESIZE_STACK_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
         reply.readException();
         data.recycle();
         reply.recycle();
     }
     @Override
-    public List<StackBoxInfo> getStackBoxes() throws RemoteException
+    public List<StackInfo> getAllStackInfos() throws RemoteException
     {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(GET_STACK_BOXES_TRANSACTION, data, reply, 0);
+        mRemote.transact(GET_ALL_STACK_INFOS_TRANSACTION, data, reply, 0);
         reply.readException();
-        ArrayList<StackBoxInfo> list = reply.createTypedArrayList(StackBoxInfo.CREATOR);
+        ArrayList<StackInfo> list = reply.createTypedArrayList(StackInfo.CREATOR);
         data.recycle();
         reply.recycle();
         return list;
     }
     @Override
-    public StackBoxInfo getStackBoxInfo(int stackBoxId) throws RemoteException
+    public StackInfo getStackInfo(int stackId) throws RemoteException
     {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(stackBoxId);
-        mRemote.transact(GET_STACK_BOX_INFO_TRANSACTION, data, reply, 0);
+        data.writeInt(stackId);
+        mRemote.transact(GET_STACK_INFO_TRANSACTION, data, reply, 0);
         reply.readException();
         int res = reply.readInt();
-        StackBoxInfo info = null;
+        StackInfo info = null;
         if (res != 0) {
-            info = StackBoxInfo.CREATOR.createFromParcel(reply);
+            info = StackInfo.CREATOR.createFromParcel(reply);
         }
         data.recycle();
         reply.recycle();
@@ -4660,5 +4652,33 @@
         reply.recycle();
     }
 
+    public IActivityContainer createActivityContainer(IBinder parentActivityToken,
+            IActivityContainerCallback callback) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(parentActivityToken);
+        data.writeStrongBinder((IBinder)callback);
+        mRemote.transact(CREATE_ACTIVITY_CONTAINER_TRANSACTION, data, reply, 0);
+        reply.readException();
+        IActivityContainer res =
+                IActivityContainer.Stub.asInterface(reply.readStrongBinder());
+        data.recycle();
+        reply.recycle();
+        return res;
+    }
+
+    public IBinder getHomeActivityToken() throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        mRemote.transact(GET_HOME_ACTIVITY_TOKEN_TRANSACTION, data, reply, 0);
+        reply.readException();
+        IBinder res = reply.readStrongBinder();
+        data.recycle();
+        reply.recycle();
+        return res;
+    }
+
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/IActivityContainer.aidl b/core/java/android/app/IActivityContainer.aidl
new file mode 100644
index 0000000..2883d25
--- /dev/null
+++ b/core/java/android/app/IActivityContainer.aidl
@@ -0,0 +1,29 @@
+/**
+ * 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 android.app;
+
+import android.app.IActivityContainerCallback;
+import android.content.Intent;
+import android.os.IBinder;
+
+/** @hide */
+interface IActivityContainer {
+    void attachToDisplay(int displayId);
+    int getStackId();
+    void detachFromDisplay();
+    void startActivity(in Intent intent);
+}
diff --git a/core/java/android/app/IActivityContainerCallback.aidl b/core/java/android/app/IActivityContainerCallback.aidl
new file mode 100644
index 0000000..55c2001
--- /dev/null
+++ b/core/java/android/app/IActivityContainerCallback.aidl
@@ -0,0 +1,24 @@
+/**
+ * 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 android.app;
+
+import android.os.IBinder;
+
+/** @hide */
+interface IActivityContainerCallback {
+    oneway void onLastActivityRemoved(IBinder container);
+}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 77c2ea0..4be1945 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -18,7 +18,7 @@
 
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityManager.RunningServiceInfo;
-import android.app.ActivityManager.StackBoxInfo;
+import android.app.ActivityManager.StackInfo;
 import android.content.ComponentName;
 import android.content.ContentProviderNative;
 import android.content.IContentProvider;
@@ -36,6 +36,7 @@
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
+import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Debug;
@@ -117,12 +118,10 @@
     public void moveTaskToBack(int task) throws RemoteException;
     public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) throws RemoteException;
     public void moveTaskBackwards(int task) throws RemoteException;
-    public int createStack(int taskId, int relativeStackBoxId, int position, float weight)
-            throws RemoteException;
     public void moveTaskToStack(int taskId, int stackId, boolean toTop) throws RemoteException;
-    public void resizeStackBox(int stackBoxId, float weight) throws RemoteException;
-    public List<StackBoxInfo> getStackBoxes() throws RemoteException;
-    public StackBoxInfo getStackBoxInfo(int stackBoxId) throws RemoteException;
+    public void resizeStack(int stackId, Rect bounds) throws RemoteException;
+    public List<StackInfo> getAllStackInfos() throws RemoteException;
+    public StackInfo getStackInfo(int stackId) throws RemoteException;
     public void setFocusedStack(int stackId) throws RemoteException;
     public int getTaskForActivity(IBinder token, boolean onlyRoot) throws RemoteException;
     /* oneway */
@@ -408,6 +407,11 @@
 
     public void performIdleMaintenance() throws RemoteException;
 
+    public IActivityContainer createActivityContainer(IBinder parentActivityToken,
+            IActivityContainerCallback callback) throws RemoteException;
+
+    public IBinder getHomeActivityToken() throws RemoteException;
+
     /*
      * Private non-Binder interfaces
      */
@@ -678,12 +682,12 @@
     int KILL_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+164;
     int SET_USER_IS_MONKEY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+165;
     int HANG_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+166;
-    int CREATE_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+167;
+    int CREATE_ACTIVITY_CONTAINER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+167;
     int MOVE_TASK_TO_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+168;
     int RESIZE_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+169;
-    int GET_STACK_BOXES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+170;
+    int GET_ALL_STACK_INFOS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+170;
     int SET_FOCUSED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+171;
-    int GET_STACK_BOX_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+172;
+    int GET_STACK_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+172;
     int CONVERT_FROM_TRANSLUCENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+173;
     int CONVERT_TO_TRANSLUCENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+174;
     int NOTIFY_ACTIVITY_DRAWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+175;
@@ -694,4 +698,5 @@
     int RELEASE_PERSISTABLE_URI_PERMISSION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+180;
     int GET_PERSISTED_URI_PERMISSIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+181;
     int APP_NOT_RESPONDING_VIA_PROVIDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+182;
+    int GET_HOME_ACTIVITY_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+183;
 }
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index 3efd3c0..181eb63 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -71,4 +71,14 @@
      * Returns the desired minimum height for the wallpaper.
      */
     int getHeightHint();
+
+    /**
+     * Returns the name of the wallpaper. Private API.
+     */
+    String getName();
+
+    /**
+     * Informs the service that wallpaper settings have been restored. Private API.
+     */
+    void settingsRestored();
 }
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index b22d5cf..a06a20b 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -79,9 +79,6 @@
     private final String mName;
     int mNativeObject; // package visibility only for Surface.java access
 
-    private static final boolean HEADLESS = "1".equals(
-        SystemProperties.get("ro.config.headless", "0"));
-
     /* flags used in constructor (keep in sync with ISurfaceComposerClient.h) */
 
     /**
@@ -232,8 +229,6 @@
                     new Throwable());
         }
 
-        checkHeadless();
-
         mName = name;
         mNativeObject = nativeCreate(session, name, w, h, format, flags);
         if (mNativeObject == 0) {
@@ -619,10 +614,4 @@
         }
         nativeScreenshot(display, consumer, width, height, minLayer, maxLayer, allLayers);
     }
-
-    private static void checkHeadless() {
-        if (HEADLESS) {
-            throw new UnsupportedOperationException("Device is headless");
-        }
-    }
 }
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 00f4adb..879e58f 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -177,7 +177,8 @@
                     userId = UserHandle.myUserId();
                 }
                 IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE);
-                IAccessibilityManager service = IAccessibilityManager.Stub.asInterface(iBinder);
+                IAccessibilityManager service = iBinder == null
+                        ? null : IAccessibilityManager.Stub.asInterface(iBinder);
                 sInstance = new AccessibilityManager(context, service, userId);
             }
         }
@@ -197,10 +198,14 @@
         mHandler = new MyHandler(context.getMainLooper());
         mService = service;
         mUserId = userId;
-
+        if (mService == null) {
+            mIsEnabled = false;
+        }
         try {
-            final int stateFlags = mService.addClient(mClient, userId);
-            setState(stateFlags);
+            if (mService != null) {
+                final int stateFlags = mService.addClient(mClient, userId);
+                setState(stateFlags);
+            }
         } catch (RemoteException re) {
             Log.e(LOG_TAG, "AccessibilityManagerService is dead", re);
         }
@@ -322,14 +327,16 @@
     public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList() {
         List<AccessibilityServiceInfo> services = null;
         try {
-            services = mService.getInstalledAccessibilityServiceList(mUserId);
-            if (DEBUG) {
-                Log.i(LOG_TAG, "Installed AccessibilityServices " + services);
+            if (mService != null) {
+                services = mService.getInstalledAccessibilityServiceList(mUserId);
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "Installed AccessibilityServices " + services);
+                }
             }
         } catch (RemoteException re) {
             Log.e(LOG_TAG, "Error while obtaining the installed AccessibilityServices. ", re);
         }
-        return Collections.unmodifiableList(services);
+        return services != null ? Collections.unmodifiableList(services) : Collections.EMPTY_LIST;
     }
 
     /**
@@ -349,14 +356,16 @@
             int feedbackTypeFlags) {
         List<AccessibilityServiceInfo> services = null;
         try {
-            services = mService.getEnabledAccessibilityServiceList(feedbackTypeFlags, mUserId);
-            if (DEBUG) {
-                Log.i(LOG_TAG, "Installed AccessibilityServices " + services);
+            if (mService != null) {
+                services = mService.getEnabledAccessibilityServiceList(feedbackTypeFlags, mUserId);
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "Installed AccessibilityServices " + services);
+                }
             }
         } catch (RemoteException re) {
             Log.e(LOG_TAG, "Error while obtaining the installed AccessibilityServices. ", re);
         }
-        return Collections.unmodifiableList(services);
+        return services != null ? Collections.unmodifiableList(services) : Collections.EMPTY_LIST;
     }
 
     /**
@@ -466,6 +475,9 @@
      */
     public int addAccessibilityInteractionConnection(IWindow windowToken,
             IAccessibilityInteractionConnection connection) {
+        if (mService == null) {
+            return View.NO_ID;
+        }
         try {
             return mService.addAccessibilityInteractionConnection(windowToken, connection, mUserId);
         } catch (RemoteException re) {
@@ -482,7 +494,9 @@
      */
     public void removeAccessibilityInteractionConnection(IWindow windowToken) {
         try {
-            mService.removeAccessibilityInteractionConnection(windowToken);
+            if (mService != null) {
+                mService.removeAccessibilityInteractionConnection(windowToken);
+            }
         } catch (RemoteException re) {
             Log.e(LOG_TAG, "Error while removing an accessibility interaction connection. ", re);
         }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b198937..e546117 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2522,7 +2522,7 @@
                  android:hasCode="false"
                  android:label="@string/android_system_label"
                  android:allowClearUserData="false"
-                 android:backupAgent="com.android.server.SystemBackupAgent"
+                 android:backupAgent="com.android.server.backup.SystemBackupAgent"
                  android:killAfterRestore="false"
                  android:icon="@drawable/ic_launcher_android"
                  android:supportsRtl="true">
diff --git a/services/common_time/Android.mk b/libs/common_time/Android.mk
similarity index 100%
rename from services/common_time/Android.mk
rename to libs/common_time/Android.mk
diff --git a/services/common_time/clock_recovery.cpp b/libs/common_time/clock_recovery.cpp
similarity index 100%
rename from services/common_time/clock_recovery.cpp
rename to libs/common_time/clock_recovery.cpp
diff --git a/services/common_time/clock_recovery.h b/libs/common_time/clock_recovery.h
similarity index 100%
rename from services/common_time/clock_recovery.h
rename to libs/common_time/clock_recovery.h
diff --git a/services/common_time/common_clock.cpp b/libs/common_time/common_clock.cpp
similarity index 100%
rename from services/common_time/common_clock.cpp
rename to libs/common_time/common_clock.cpp
diff --git a/services/common_time/common_clock.h b/libs/common_time/common_clock.h
similarity index 100%
rename from services/common_time/common_clock.h
rename to libs/common_time/common_clock.h
diff --git a/services/common_time/common_clock_service.cpp b/libs/common_time/common_clock_service.cpp
similarity index 100%
rename from services/common_time/common_clock_service.cpp
rename to libs/common_time/common_clock_service.cpp
diff --git a/services/common_time/common_clock_service.h b/libs/common_time/common_clock_service.h
similarity index 100%
rename from services/common_time/common_clock_service.h
rename to libs/common_time/common_clock_service.h
diff --git a/services/common_time/common_time_config_service.cpp b/libs/common_time/common_time_config_service.cpp
similarity index 100%
rename from services/common_time/common_time_config_service.cpp
rename to libs/common_time/common_time_config_service.cpp
diff --git a/services/common_time/common_time_config_service.h b/libs/common_time/common_time_config_service.h
similarity index 100%
rename from services/common_time/common_time_config_service.h
rename to libs/common_time/common_time_config_service.h
diff --git a/services/common_time/common_time_server.cpp b/libs/common_time/common_time_server.cpp
similarity index 100%
rename from services/common_time/common_time_server.cpp
rename to libs/common_time/common_time_server.cpp
diff --git a/services/common_time/common_time_server.h b/libs/common_time/common_time_server.h
similarity index 100%
rename from services/common_time/common_time_server.h
rename to libs/common_time/common_time_server.h
diff --git a/services/common_time/common_time_server_api.cpp b/libs/common_time/common_time_server_api.cpp
similarity index 100%
rename from services/common_time/common_time_server_api.cpp
rename to libs/common_time/common_time_server_api.cpp
diff --git a/services/common_time/common_time_server_packets.cpp b/libs/common_time/common_time_server_packets.cpp
similarity index 100%
rename from services/common_time/common_time_server_packets.cpp
rename to libs/common_time/common_time_server_packets.cpp
diff --git a/services/common_time/common_time_server_packets.h b/libs/common_time/common_time_server_packets.h
similarity index 100%
rename from services/common_time/common_time_server_packets.h
rename to libs/common_time/common_time_server_packets.h
diff --git a/services/common_time/diag_thread.cpp b/libs/common_time/diag_thread.cpp
similarity index 100%
rename from services/common_time/diag_thread.cpp
rename to libs/common_time/diag_thread.cpp
diff --git a/services/common_time/diag_thread.h b/libs/common_time/diag_thread.h
similarity index 100%
rename from services/common_time/diag_thread.h
rename to libs/common_time/diag_thread.h
diff --git a/services/common_time/main.cpp b/libs/common_time/main.cpp
similarity index 100%
rename from services/common_time/main.cpp
rename to libs/common_time/main.cpp
diff --git a/services/common_time/utils.cpp b/libs/common_time/utils.cpp
similarity index 100%
rename from services/common_time/utils.cpp
rename to libs/common_time/utils.cpp
diff --git a/services/common_time/utils.h b/libs/common_time/utils.h
similarity index 100%
rename from services/common_time/utils.h
rename to libs/common_time/utils.h
diff --git a/services/input/Android.mk b/libs/input/Android.mk
similarity index 100%
rename from services/input/Android.mk
rename to libs/input/Android.mk
diff --git a/services/input/EventHub.cpp b/libs/input/EventHub.cpp
similarity index 100%
rename from services/input/EventHub.cpp
rename to libs/input/EventHub.cpp
diff --git a/services/input/EventHub.h b/libs/input/EventHub.h
similarity index 100%
rename from services/input/EventHub.h
rename to libs/input/EventHub.h
diff --git a/services/input/InputApplication.cpp b/libs/input/InputApplication.cpp
similarity index 100%
rename from services/input/InputApplication.cpp
rename to libs/input/InputApplication.cpp
diff --git a/services/input/InputApplication.h b/libs/input/InputApplication.h
similarity index 100%
rename from services/input/InputApplication.h
rename to libs/input/InputApplication.h
diff --git a/services/input/InputDispatcher.cpp b/libs/input/InputDispatcher.cpp
similarity index 100%
rename from services/input/InputDispatcher.cpp
rename to libs/input/InputDispatcher.cpp
diff --git a/services/input/InputDispatcher.h b/libs/input/InputDispatcher.h
similarity index 100%
rename from services/input/InputDispatcher.h
rename to libs/input/InputDispatcher.h
diff --git a/services/input/InputListener.cpp b/libs/input/InputListener.cpp
similarity index 100%
rename from services/input/InputListener.cpp
rename to libs/input/InputListener.cpp
diff --git a/services/input/InputListener.h b/libs/input/InputListener.h
similarity index 100%
rename from services/input/InputListener.h
rename to libs/input/InputListener.h
diff --git a/services/input/InputManager.cpp b/libs/input/InputManager.cpp
similarity index 100%
rename from services/input/InputManager.cpp
rename to libs/input/InputManager.cpp
diff --git a/services/input/InputManager.h b/libs/input/InputManager.h
similarity index 100%
rename from services/input/InputManager.h
rename to libs/input/InputManager.h
diff --git a/services/input/InputReader.cpp b/libs/input/InputReader.cpp
similarity index 100%
rename from services/input/InputReader.cpp
rename to libs/input/InputReader.cpp
diff --git a/services/input/InputReader.h b/libs/input/InputReader.h
similarity index 100%
rename from services/input/InputReader.h
rename to libs/input/InputReader.h
diff --git a/services/input/InputWindow.cpp b/libs/input/InputWindow.cpp
similarity index 100%
rename from services/input/InputWindow.cpp
rename to libs/input/InputWindow.cpp
diff --git a/services/input/InputWindow.h b/libs/input/InputWindow.h
similarity index 100%
rename from services/input/InputWindow.h
rename to libs/input/InputWindow.h
diff --git a/services/input/PointerController.cpp b/libs/input/PointerController.cpp
similarity index 100%
rename from services/input/PointerController.cpp
rename to libs/input/PointerController.cpp
diff --git a/services/input/PointerController.h b/libs/input/PointerController.h
similarity index 100%
rename from services/input/PointerController.h
rename to libs/input/PointerController.h
diff --git a/services/input/SpriteController.cpp b/libs/input/SpriteController.cpp
similarity index 100%
rename from services/input/SpriteController.cpp
rename to libs/input/SpriteController.cpp
diff --git a/services/input/SpriteController.h b/libs/input/SpriteController.h
similarity index 100%
rename from services/input/SpriteController.h
rename to libs/input/SpriteController.h
diff --git a/services/input/tests/Android.mk b/libs/input/tests/Android.mk
similarity index 100%
rename from services/input/tests/Android.mk
rename to libs/input/tests/Android.mk
diff --git a/services/input/tests/InputDispatcher_test.cpp b/libs/input/tests/InputDispatcher_test.cpp
similarity index 100%
rename from services/input/tests/InputDispatcher_test.cpp
rename to libs/input/tests/InputDispatcher_test.cpp
diff --git a/services/input/tests/InputReader_test.cpp b/libs/input/tests/InputReader_test.cpp
similarity index 100%
rename from services/input/tests/InputReader_test.cpp
rename to libs/input/tests/InputReader_test.cpp
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index c33bd35..f33ab40 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -231,7 +231,6 @@
     /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */
     boolean mEnableShiftMenuBugReports = false;
 
-    boolean mHeadless;
     boolean mSafeMode;
     WindowState mStatusBar = null;
     int mStatusBarHeight;
@@ -855,7 +854,6 @@
         mContext = context;
         mWindowManager = windowManager;
         mWindowManagerFuncs = windowManagerFuncs;
-        mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
         mHandler = new PolicyHandler();
         mOrientationListener = new MyOrientationListener(mContext, mHandler);
         try {
@@ -3602,9 +3600,6 @@
 
     /** {@inheritDoc} */
     public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
-        // do nothing if headless
-        if (mHeadless) return;
-
         // lid changed state
         final int newLidState = lidOpen ? LID_OPEN : LID_CLOSED;
         if (newLidState == mLidState) {
@@ -3837,7 +3832,7 @@
         //        the device some other way (which is why we have an exemption here for injected
         //        events).
         int result;
-        if ((isScreenOn && !mHeadless) || (isInjected && !isWakeKey)) {
+        if (isScreenOn || (isInjected && !isWakeKey)) {
             // When the screen is on or if the key is injected pass the key to the application.
             result = ACTION_PASS_TO_USER;
         } else {
@@ -4663,10 +4658,9 @@
     /** {@inheritDoc} */
     @Override
     public void systemReady() {
-        if (!mHeadless) {
-            mKeyguardDelegate = new KeyguardServiceDelegate(mContext, null);
-            mKeyguardDelegate.onSystemReady();
-        }
+        mKeyguardDelegate = new KeyguardServiceDelegate(mContext, null);
+        mKeyguardDelegate.onSystemReady();
+
         synchronized (mLock) {
             updateOrientationListenerLp();
             mSystemReady = true;
@@ -4693,7 +4687,6 @@
 
     /** {@inheritDoc} */
     public void showBootMessage(final CharSequence msg, final boolean always) {
-        if (mHeadless) return;
         mHandler.post(new Runnable() {
             @Override public void run() {
                 if (mBootMsgDialog == null) {
diff --git a/services/Android.mk b/services/Android.mk
new file mode 100644
index 0000000..8bd7629
--- /dev/null
+++ b/services/Android.mk
@@ -0,0 +1,45 @@
+LOCAL_PATH:= $(call my-dir)
+
+# the java library
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES :=
+
+# TODO: Move this to the product makefiles
+REQUIRED_SERVICES := core accessibility appwidget backup devicepolicy print
+
+include $(patsubst %,$(LOCAL_PATH)/%/java/service.mk,$(REQUIRED_SERVICES))
+
+LOCAL_MODULE:= services
+
+LOCAL_JAVA_LIBRARIES := android.policy conscrypt telephony-common
+
+#LOCAL_PROGUARD_ENABLED := full
+#LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+
+include $(BUILD_JAVA_LIBRARY)
+
+include $(BUILD_DROIDDOC)
+
+# native library
+# =============================================================
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES :=
+LOCAL_SHARED_LIBRARIES :=
+
+# include all the jni subdirs to collect their sources
+include $(wildcard $(LOCAL_PATH)/*/jni/Android.mk)
+
+LOCAL_CFLAGS += -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES
+
+ifeq ($(WITH_MALLOC_LEAK_CHECK),true)
+    LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
+endif
+
+LOCAL_MODULE:= libandroid_servers
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
similarity index 100%
rename from services/java/com/android/server/accessibility/AccessibilityInputFilter.java
rename to services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
similarity index 100%
rename from services/java/com/android/server/accessibility/AccessibilityManagerService.java
rename to services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
diff --git a/services/java/com/android/server/accessibility/EventStreamTransformation.java b/services/accessibility/java/com/android/server/accessibility/EventStreamTransformation.java
similarity index 100%
rename from services/java/com/android/server/accessibility/EventStreamTransformation.java
rename to services/accessibility/java/com/android/server/accessibility/EventStreamTransformation.java
diff --git a/services/java/com/android/server/accessibility/GestureUtils.java b/services/accessibility/java/com/android/server/accessibility/GestureUtils.java
similarity index 100%
rename from services/java/com/android/server/accessibility/GestureUtils.java
rename to services/accessibility/java/com/android/server/accessibility/GestureUtils.java
diff --git a/services/java/com/android/server/accessibility/ScreenMagnifier.java b/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java
similarity index 100%
rename from services/java/com/android/server/accessibility/ScreenMagnifier.java
rename to services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java
diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
similarity index 100%
rename from services/java/com/android/server/accessibility/TouchExplorer.java
rename to services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
diff --git a/services/accessibility/java/service.mk b/services/accessibility/java/service.mk
new file mode 100644
index 0000000..5e8f375
--- /dev/null
+++ b/services/accessibility/java/service.mk
@@ -0,0 +1,11 @@
+# Include only if the service is required
+ifneq ($(findstring accessibility,$(REQUIRED_SERVICES)),)
+
+SUB_DIR := accessibility/java
+
+LOCAL_SRC_FILES += \
+      $(call all-java-files-under,$(SUB_DIR))
+
+#DEFINED_SERVICES += com.android.server.accessibility.AccessibilityManagerService
+
+endif
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java
new file mode 100644
index 0000000..3378e3d
--- /dev/null
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2007 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.appwidget;
+
+import android.app.ActivityManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.widget.RemoteViews;
+
+import com.android.internal.appwidget.IAppWidgetHost;
+import com.android.internal.appwidget.IAppWidgetService;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.SystemService;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.Locale;
+
+
+/**
+ * SystemService that publishes an IAppWidgetService.
+ */
+public class AppWidgetService extends SystemService {
+
+    static final String TAG = "AppWidgetService";
+
+    Context mContext;
+    Handler mSaveStateHandler;
+
+    SparseArray<AppWidgetServiceImpl> mAppWidgetServices;
+
+    @Override
+    public void onCreate(Context context) {
+        mContext = context;
+
+        mSaveStateHandler = BackgroundThread.getHandler();
+
+        mAppWidgetServices = new SparseArray<AppWidgetServiceImpl>(5);
+        AppWidgetServiceImpl primary = new AppWidgetServiceImpl(context, 0, mSaveStateHandler);
+        mAppWidgetServices.append(0, primary);
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService(Context.APPWIDGET_SERVICE, mServiceImpl);
+    }
+
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
+            mServiceImpl.systemRunning(isSafeMode());
+        }
+    }
+
+    private final AppWidgetServiceStub mServiceImpl = new AppWidgetServiceStub();
+
+    private class AppWidgetServiceStub extends IAppWidgetService.Stub {
+
+        private boolean mSafeMode;
+        private Locale mLocale;
+        private PackageManager mPackageManager;
+
+        public void systemRunning(boolean safeMode) {
+            mSafeMode = safeMode;
+
+            mAppWidgetServices.get(0).systemReady(safeMode);
+
+            // Register for the boot completed broadcast, so we can send the
+            // ENABLE broacasts. If we try to send them now, they time out,
+            // because the system isn't ready to handle them yet.
+            mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
+                    new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
+
+            // Register for configuration changes so we can update the names
+            // of the widgets when the locale changes.
+            mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
+                    new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED), null, null);
+
+            // Register for broadcasts about package install, etc., so we can
+            // update the provider list.
+            IntentFilter filter = new IntentFilter();
+            filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+            filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+            filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+            filter.addDataScheme("package");
+            mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
+                    filter, null, null);
+            // Register for events related to sdcard installation.
+            IntentFilter sdFilter = new IntentFilter();
+            sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+            sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+            mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
+                    sdFilter, null, null);
+
+            IntentFilter userFilter = new IntentFilter();
+            userFilter.addAction(Intent.ACTION_USER_REMOVED);
+            userFilter.addAction(Intent.ACTION_USER_STOPPING);
+            mContext.registerReceiver(new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
+                        onUserRemoved(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+                                UserHandle.USER_NULL));
+                    } else if (Intent.ACTION_USER_STOPPING.equals(intent.getAction())) {
+                        onUserStopping(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+                                UserHandle.USER_NULL));
+                    }
+                }
+            }, userFilter);
+        }
+
+        @Override
+        public int allocateAppWidgetId(String packageName, int hostId, int userId)
+                throws RemoteException {
+            return getImplForUser(userId).allocateAppWidgetId(packageName, hostId);
+        }
+
+        @Override
+        public int[] getAppWidgetIdsForHost(int hostId, int userId) throws RemoteException {
+            return getImplForUser(userId).getAppWidgetIdsForHost(hostId);
+        }
+
+        @Override
+        public void deleteAppWidgetId(int appWidgetId, int userId) throws RemoteException {
+            getImplForUser(userId).deleteAppWidgetId(appWidgetId);
+        }
+
+        @Override
+        public void deleteHost(int hostId, int userId) throws RemoteException {
+            getImplForUser(userId).deleteHost(hostId);
+        }
+
+        @Override
+        public void deleteAllHosts(int userId) throws RemoteException {
+            getImplForUser(userId).deleteAllHosts();
+        }
+
+        @Override
+        public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options,
+                int userId) throws RemoteException {
+            getImplForUser(userId).bindAppWidgetId(appWidgetId, provider, options);
+        }
+
+        @Override
+        public boolean bindAppWidgetIdIfAllowed(
+                String packageName, int appWidgetId, ComponentName provider, Bundle options,
+                int userId) throws RemoteException {
+            return getImplForUser(userId).bindAppWidgetIdIfAllowed(
+                    packageName, appWidgetId, provider, options);
+        }
+
+        @Override
+        public boolean hasBindAppWidgetPermission(String packageName, int userId)
+                throws RemoteException {
+            return getImplForUser(userId).hasBindAppWidgetPermission(packageName);
+        }
+
+        @Override
+        public void setBindAppWidgetPermission(String packageName, boolean permission, int userId)
+                throws RemoteException {
+            getImplForUser(userId).setBindAppWidgetPermission(packageName, permission);
+        }
+
+        @Override
+        public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection,
+                int userId) throws RemoteException {
+            getImplForUser(userId).bindRemoteViewsService(appWidgetId, intent, connection);
+        }
+
+        @Override
+        public int[] startListening(IAppWidgetHost host, String packageName, int hostId,
+                List<RemoteViews> updatedViews, int userId) throws RemoteException {
+            return getImplForUser(userId).startListening(host, packageName, hostId, updatedViews);
+        }
+
+        public void onUserRemoved(int userId) {
+            if (userId < 1) return;
+            synchronized (mAppWidgetServices) {
+                AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
+                mAppWidgetServices.remove(userId);
+
+                if (impl == null) {
+                    AppWidgetServiceImpl.getSettingsFile(userId).delete();
+                } else {
+                    impl.onUserRemoved();
+                }
+            }
+        }
+
+        public void onUserStopping(int userId) {
+            if (userId < 1) return;
+            synchronized (mAppWidgetServices) {
+                AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
+                if (impl != null) {
+                    mAppWidgetServices.remove(userId);
+                    impl.onUserStopping();
+                }
+            }
+        }
+
+        private void checkPermission(int userId) {
+            int realUserId = ActivityManager.handleIncomingUser(
+                    Binder.getCallingPid(),
+                    Binder.getCallingUid(),
+                    userId,
+                    false, /* allowAll */
+                    true, /* requireFull */
+                    this.getClass().getSimpleName(),
+                    this.getClass().getPackage().getName());
+        }
+
+        private AppWidgetServiceImpl getImplForUser(int userId) {
+            checkPermission(userId);
+            boolean sendInitial = false;
+            AppWidgetServiceImpl service;
+            synchronized (mAppWidgetServices) {
+                service = mAppWidgetServices.get(userId);
+                if (service == null) {
+                    Slog.i(TAG, "Unable to find AppWidgetServiceImpl for user " + userId
+                            + ", adding");
+                    // TODO: Verify that it's a valid user
+                    service = new AppWidgetServiceImpl(mContext, userId, mSaveStateHandler);
+                    service.systemReady(mSafeMode);
+                    // Assume that BOOT_COMPLETED was received, as this is a non-primary user.
+                    mAppWidgetServices.append(userId, service);
+                    sendInitial = true;
+                }
+            }
+            if (sendInitial) {
+                service.sendInitialBroadcasts();
+            }
+            return service;
+        }
+
+        @Override
+        public int[] getAppWidgetIds(ComponentName provider, int userId) throws RemoteException {
+            return getImplForUser(userId).getAppWidgetIds(provider);
+        }
+
+        @Override
+        public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId, int userId)
+                throws RemoteException {
+            return getImplForUser(userId).getAppWidgetInfo(appWidgetId);
+        }
+
+        @Override
+        public RemoteViews getAppWidgetViews(int appWidgetId, int userId) throws RemoteException {
+            return getImplForUser(userId).getAppWidgetViews(appWidgetId);
+        }
+
+        @Override
+        public void updateAppWidgetOptions(int appWidgetId, Bundle options, int userId) {
+            getImplForUser(userId).updateAppWidgetOptions(appWidgetId, options);
+        }
+
+        @Override
+        public Bundle getAppWidgetOptions(int appWidgetId, int userId) {
+            return getImplForUser(userId).getAppWidgetOptions(appWidgetId);
+        }
+
+        @Override
+        public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter, int userId)
+                throws RemoteException {
+            return getImplForUser(userId).getInstalledProviders(categoryFilter);
+        }
+
+        @Override
+        public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId, int userId)
+                throws RemoteException {
+            getImplForUser(userId).notifyAppWidgetViewDataChanged(
+                    appWidgetIds, viewId);
+        }
+
+        @Override
+        public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views, int userId)
+                throws RemoteException {
+            getImplForUser(userId).partiallyUpdateAppWidgetIds(
+                    appWidgetIds, views);
+        }
+
+        @Override
+        public void stopListening(int hostId, int userId) throws RemoteException {
+            getImplForUser(userId).stopListening(hostId);
+        }
+
+        @Override
+        public void unbindRemoteViewsService(int appWidgetId, Intent intent, int userId)
+                throws RemoteException {
+            getImplForUser(userId).unbindRemoteViewsService(
+                    appWidgetId, intent);
+        }
+
+        @Override
+        public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views, int userId)
+                throws RemoteException {
+            getImplForUser(userId).updateAppWidgetIds(appWidgetIds, views);
+        }
+
+        @Override
+        public void updateAppWidgetProvider(ComponentName provider, RemoteViews views, int userId)
+                throws RemoteException {
+            getImplForUser(userId).updateAppWidgetProvider(provider, views);
+        }
+
+        @Override
+        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
+
+            // Dump the state of all the app widget providers
+            synchronized (mAppWidgetServices) {
+                IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
+                for (int i = 0; i < mAppWidgetServices.size(); i++) {
+                    pw.println("User: " + mAppWidgetServices.keyAt(i));
+                    ipw.increaseIndent();
+                    AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
+                    service.dump(fd, ipw, args);
+                    ipw.decreaseIndent();
+                }
+            }
+        }
+
+        BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+            public void onReceive(Context context, Intent intent) {
+                String action = intent.getAction();
+                // Slog.d(TAG, "received " + action);
+                if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
+                    int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+                    if (userId >= 0) {
+                        getImplForUser(userId).sendInitialBroadcasts();
+                    } else {
+                        Slog.w(TAG, "Incorrect user handle supplied in " + intent);
+                    }
+                } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
+                    for (int i = 0; i < mAppWidgetServices.size(); i++) {
+                        AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
+                        service.onConfigurationChanged();
+                    }
+                } else {
+                    int sendingUser = getSendingUserId();
+                    if (sendingUser == UserHandle.USER_ALL) {
+                        for (int i = 0; i < mAppWidgetServices.size(); i++) {
+                            AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
+                            service.onBroadcastReceived(intent);
+                        }
+                    } else {
+                        AppWidgetServiceImpl service = mAppWidgetServices.get(sendingUser);
+                        if (service != null) {
+                            service.onBroadcastReceived(intent);
+                        }
+                    }
+                }
+            }
+        };
+    }
+}
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
similarity index 99%
rename from services/java/com/android/server/AppWidgetServiceImpl.java
rename to services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 69ae846..98dead3 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.appwidget;
 
 import android.app.AlarmManager;
 import android.app.AppGlobals;
diff --git a/services/appwidget/java/service.mk b/services/appwidget/java/service.mk
new file mode 100644
index 0000000..0e33446
--- /dev/null
+++ b/services/appwidget/java/service.mk
@@ -0,0 +1,11 @@
+# Include only if the service is required
+ifneq ($(findstring appwidget,$(REQUIRED_SERVICES)),)
+
+SUB_DIR := appwidget/java
+
+LOCAL_SRC_FILES += \
+      $(call all-java-files-under,$(SUB_DIR))
+
+#DEFINED_SERVICES += com.android.server.appwidget.AppWidgetService
+
+endif
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
similarity index 99%
rename from services/java/com/android/server/BackupManagerService.java
rename to services/backup/java/com/android/server/backup/BackupManagerService.java
index 00bfee7..c6dc5e6 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.backup;
 
 import android.app.ActivityManagerNative;
 import android.app.AlarmManager;
@@ -83,7 +83,9 @@
 import com.android.internal.backup.IBackupTransport;
 import com.android.internal.backup.IObbBackupService;
 import com.android.internal.backup.LocalTransport;
-import com.android.server.PackageManagerBackupAgent.Metadata;
+import com.android.server.EventLogTags;
+import com.android.server.SystemService;
+import com.android.server.backup.PackageManagerBackupAgent.Metadata;
 
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
@@ -135,7 +137,8 @@
 import javax.crypto.spec.PBEKeySpec;
 import javax.crypto.spec.SecretKeySpec;
 
-class BackupManagerService extends IBackupManager.Stub {
+public class BackupManagerService extends IBackupManager.Stub {
+
     private static final String TAG = "BackupManagerService";
     private static final boolean DEBUG = true;
     private static final boolean MORE_DEBUG = false;
@@ -1178,7 +1181,8 @@
         // First, on an encrypted device we require matching the device pw
         final boolean isEncrypted;
         try {
-            isEncrypted = (mMountService.getEncryptionState() != MountService.ENCRYPTION_STATE_NONE);
+            isEncrypted = (mMountService.getEncryptionState() !=
+                    IMountService.ENCRYPTION_STATE_NONE);
             if (isEncrypted) {
                 if (DEBUG) {
                     Slog.i(TAG, "Device encrypted; verifying against device data pw");
@@ -5437,7 +5441,8 @@
 
                         boolean isEncrypted;
                         try {
-                            isEncrypted = (mMountService.getEncryptionState() != MountService.ENCRYPTION_STATE_NONE);
+                            isEncrypted = (mMountService.getEncryptionState() !=
+                                    IMountService.ENCRYPTION_STATE_NONE);
                             if (isEncrypted) Slog.w(TAG, "Device is encrypted; forcing enc password");
                         } catch (RemoteException e) {
                             // couldn't contact the mount service; fail "safe" and assume encryption
@@ -6086,7 +6091,7 @@
                     }
                 }
 
-                // clean up the BackupManagerService side of the bookkeeping
+                // clean up the BackupManagerImpl side of the bookkeeping
                 // and cancel any pending timeout message
                 mBackupManager.clearRestoreSession(mSession);
             }
diff --git a/services/backup/java/com/android/server/backup/BackupManagerSystemService.java b/services/backup/java/com/android/server/backup/BackupManagerSystemService.java
new file mode 100644
index 0000000..db2c94a
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/BackupManagerSystemService.java
@@ -0,0 +1,36 @@
+/*
+ * 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.backup;
+
+import android.content.Context;
+
+import com.android.server.SystemService;
+
+public class BackupManagerSystemService extends SystemService {
+    private BackupManagerService mBackupManagerImpl;
+
+    @Override
+    public void onCreate(Context context) {
+        mBackupManagerImpl = new BackupManagerService(context);
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService(Context.BACKUP_SERVICE, mBackupManagerImpl);
+    }
+}
+
diff --git a/services/java/com/android/server/PackageManagerBackupAgent.java b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
similarity index 99%
rename from services/java/com/android/server/PackageManagerBackupAgent.java
rename to services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
index 77bddb0..495da88 100644
--- a/services/java/com/android/server/PackageManagerBackupAgent.java
+++ b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.backup;
 
 import android.app.backup.BackupAgent;
 import android.app.backup.BackupDataInput;
diff --git a/services/java/com/android/server/SystemBackupAgent.java b/services/backup/java/com/android/server/backup/SystemBackupAgent.java
similarity index 79%
rename from services/java/com/android/server/SystemBackupAgent.java
rename to services/backup/java/com/android/server/backup/SystemBackupAgent.java
index 8cf273d..26e2e2a 100644
--- a/services/java/com/android/server/SystemBackupAgent.java
+++ b/services/backup/java/com/android/server/backup/SystemBackupAgent.java
@@ -14,9 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.backup;
 
 
+import android.app.IWallpaperManager;
 import android.app.backup.BackupDataInput;
 import android.app.backup.BackupDataOutput;
 import android.app.backup.BackupAgentHelper;
@@ -26,11 +27,11 @@
 import android.content.Context;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.util.Slog;
 
-
 import java.io.File;
 import java.io.IOException;
 
@@ -63,16 +64,23 @@
     public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
             ParcelFileDescriptor newState) throws IOException {
         // We only back up the data under the current "wallpaper" schema with metadata
-        WallpaperManagerService wallpaper = (WallpaperManagerService)ServiceManager.getService(
+        IWallpaperManager wallpaper = (IWallpaperManager)ServiceManager.getService(
                 Context.WALLPAPER_SERVICE);
         String[] files = new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO };
         String[] keys = new String[] { WALLPAPER_IMAGE_KEY, WALLPAPER_INFO_KEY };
-        if (wallpaper != null && wallpaper.getName() != null && wallpaper.getName().length() > 0) {
-            // When the wallpaper has a name, back up the info by itself.
-            // TODO: Don't rely on the innards of the service object like this!
-            // TODO: Send a delete for any stored wallpaper image in this case?
-            files = new String[] { WALLPAPER_INFO };
-            keys = new String[] { WALLPAPER_INFO_KEY };
+        if (wallpaper != null) {
+            try {
+                final String wallpaperName = wallpaper.getName();
+                if (wallpaperName != null && wallpaperName.length() > 0) {
+                    // When the wallpaper has a name, back up the info by itself.
+                    // TODO: Don't rely on the innards of the service object like this!
+                    // TODO: Send a delete for any stored wallpaper image in this case?
+                    files = new String[] { WALLPAPER_INFO };
+                    keys = new String[] { WALLPAPER_INFO_KEY };
+                }
+            } catch (RemoteException re) {
+                Slog.e(TAG, "Couldn't get wallpaper name\n" + re);
+            }
         }
         addHelper("wallpaper", new WallpaperBackupHelper(SystemBackupAgent.this, files, keys));
         super.onBackup(oldState, data, newState);
@@ -109,9 +117,15 @@
         try {
             super.onRestore(data, appVersionCode, newState);
 
-            WallpaperManagerService wallpaper = (WallpaperManagerService)ServiceManager.getService(
+            IWallpaperManager wallpaper = (IWallpaperManager) ServiceManager.getService(
                     Context.WALLPAPER_SERVICE);
-            wallpaper.settingsRestored();
+            if (wallpaper != null) {
+                try {
+                    wallpaper.settingsRestored();
+                } catch (RemoteException re) {
+                    Slog.e(TAG, "Couldn't restore settings\n" + re);
+                }
+            }
         } catch (IOException ex) {
             // If there was a failure, delete everything for the wallpaper, this is too aggressive,
             // but this is hopefully a rare failure.
@@ -149,10 +163,16 @@
             FullBackup.restoreFile(data, size, type, mode, mtime, outFile);
 
             if (restoredWallpaper) {
-                WallpaperManagerService wallpaper =
-                        (WallpaperManagerService)ServiceManager.getService(
+                IWallpaperManager wallpaper =
+                        (IWallpaperManager)ServiceManager.getService(
                         Context.WALLPAPER_SERVICE);
-                wallpaper.settingsRestored();
+                if (wallpaper != null) {
+                    try {
+                        wallpaper.settingsRestored();
+                    } catch (RemoteException re) {
+                        Slog.e(TAG, "Couldn't restore settings\n" + re);
+                    }
+                }
             }
         } catch (IOException e) {
             if (restoredWallpaper) {
diff --git a/services/backup/java/service.mk b/services/backup/java/service.mk
new file mode 100644
index 0000000..bd22b95
--- /dev/null
+++ b/services/backup/java/service.mk
@@ -0,0 +1,11 @@
+# Include only if the service is required
+ifneq ($(findstring backup,$(REQUIRED_SERVICES)),)
+
+SUB_DIR := backup/java
+
+LOCAL_SRC_FILES += \
+      $(call all-java-files-under,$(SUB_DIR))
+
+#DEFINED_SERVICES += com.android.server.backup.BackupManagerService
+
+endif
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
similarity index 88%
rename from services/java/com/android/server/AlarmManagerService.java
rename to services/core/java/com/android/server/AlarmManagerService.java
index 2e1b0af..3cdf170 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -31,6 +31,7 @@
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Message;
 import android.os.PowerManager;
 import android.os.SystemClock;
@@ -64,54 +65,51 @@
 
 import com.android.internal.util.LocalLog;
 
-class AlarmManagerService extends IAlarmManager.Stub {
+class AlarmManagerService extends SystemService {
     // The threshold for how long an alarm can be late before we print a
     // warning message.  The time duration is in milliseconds.
     private static final long LATE_ALARM_THRESHOLD = 10 * 1000;
 
     private static final int RTC_WAKEUP_MASK = 1 << RTC_WAKEUP;
     private static final int RTC_MASK = 1 << RTC;
-    private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << ELAPSED_REALTIME_WAKEUP; 
+    private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << ELAPSED_REALTIME_WAKEUP;
     private static final int ELAPSED_REALTIME_MASK = 1 << ELAPSED_REALTIME;
-    private static final int TIME_CHANGED_MASK = 1 << 16;
-    private static final int IS_WAKEUP_MASK = RTC_WAKEUP_MASK|ELAPSED_REALTIME_WAKEUP_MASK;
+    static final int TIME_CHANGED_MASK = 1 << 16;
+    static final int IS_WAKEUP_MASK = RTC_WAKEUP_MASK|ELAPSED_REALTIME_WAKEUP_MASK;
 
     // Mask for testing whether a given alarm type is wakeup vs non-wakeup
-    private static final int TYPE_NONWAKEUP_MASK = 0x1; // low bit => non-wakeup
+    static final int TYPE_NONWAKEUP_MASK = 0x1; // low bit => non-wakeup
 
-    private static final String TAG = "AlarmManager";
-    private static final String ClockReceiver_TAG = "ClockReceiver";
-    private static final boolean localLOGV = false;
-    private static final boolean DEBUG_BATCH = localLOGV || false;
-    private static final boolean DEBUG_VALIDATE = localLOGV || false;
-    private static final int ALARM_EVENT = 1;
-    private static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
+    static final String TAG = "AlarmManager";
+    static final String ClockReceiver_TAG = "ClockReceiver";
+    static final boolean localLOGV = false;
+    static final boolean DEBUG_BATCH = localLOGV || false;
+    static final boolean DEBUG_VALIDATE = localLOGV || false;
+    static final int ALARM_EVENT = 1;
+    static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
     
-    private static final Intent mBackgroundIntent
+    static final Intent mBackgroundIntent
             = new Intent().addFlags(Intent.FLAG_FROM_BACKGROUND);
-    private static final IncreasingTimeOrder sIncreasingTimeOrder = new IncreasingTimeOrder();
+    static final IncreasingTimeOrder sIncreasingTimeOrder = new IncreasingTimeOrder();
     
-    private static final boolean WAKEUP_STATS = false;
+    static final boolean WAKEUP_STATS = false;
 
-    private final Context mContext;
+    final LocalLog mLog = new LocalLog(TAG);
 
-    private final LocalLog mLog = new LocalLog(TAG);
+    final Object mLock = new Object();
 
-    private Object mLock = new Object();
-
-    private long mNativeData;
+    long mNativeData;
     private long mNextWakeup;
     private long mNextNonWakeup;
-    private int mBroadcastRefCount = 0;
-    private PowerManager.WakeLock mWakeLock;
-    private ArrayList<InFlight> mInFlight = new ArrayList<InFlight>();
-    private final AlarmThread mWaitThread = new AlarmThread();
-    private final AlarmHandler mHandler = new AlarmHandler();
-    private ClockReceiver mClockReceiver;
+    int mBroadcastRefCount = 0;
+    PowerManager.WakeLock mWakeLock;
+    ArrayList<InFlight> mInFlight = new ArrayList<InFlight>();
+    final AlarmHandler mHandler = new AlarmHandler();
+    ClockReceiver mClockReceiver;
     private UninstallReceiver mUninstallReceiver;
-    private final ResultReceiver mResultReceiver = new ResultReceiver();
-    private final PendingIntent mTimeTickSender;
-    private final PendingIntent mDateChangeSender;
+    final ResultReceiver mResultReceiver = new ResultReceiver();
+    PendingIntent mTimeTickSender;
+    PendingIntent mDateChangeSender;
 
     class WakeupEvent {
         public long when;
@@ -125,8 +123,8 @@
         }
     }
 
-    private final LinkedList<WakeupEvent> mRecentWakeups = new LinkedList<WakeupEvent>();
-    private final long RECENT_WAKEUP_PERIOD = 1000L * 60 * 60 * 24; // one day
+    final LinkedList<WakeupEvent> mRecentWakeups = new LinkedList<WakeupEvent>();
+    final long RECENT_WAKEUP_PERIOD = 1000L * 60 * 60 * 24; // one day
 
     static final class Batch {
         long start;     // These endpoints are always in ELAPSED
@@ -317,9 +315,9 @@
     }
     
     // minimum recurrence period or alarm futurity for us to be able to fuzz it
-    private static final long MIN_FUZZABLE_INTERVAL = 10000;
-    private static final BatchTimeOrder sBatchOrder = new BatchTimeOrder();
-    private final ArrayList<Batch> mAlarmBatches = new ArrayList<Batch>();
+    static final long MIN_FUZZABLE_INTERVAL = 10000;
+    static final BatchTimeOrder sBatchOrder = new BatchTimeOrder();
+    final ArrayList<Batch> mAlarmBatches = new ArrayList<Batch>();
 
     static long convertToElapsed(long when, int type) {
         final boolean isRtc = (type == RTC || type == RTC_WAKEUP);
@@ -403,7 +401,7 @@
         }
     }
 
-    private static final class InFlight extends Intent {
+    static final class InFlight extends Intent {
         final PendingIntent mPendingIntent;
         final WorkSource mWorkSource;
         final Pair<String, ComponentName> mTarget;
@@ -427,7 +425,7 @@
         }
     }
 
-    private static final class FilterStats {
+    static final class FilterStats {
         final BroadcastStats mBroadcastStats;
         final Pair<String, ComponentName> mTarget;
 
@@ -443,7 +441,7 @@
         }
     }
     
-    private static final class BroadcastStats {
+    static final class BroadcastStats {
         final String mPackageName;
 
         long aggregateTime;
@@ -459,47 +457,48 @@
         }
     }
     
-    private final HashMap<String, BroadcastStats> mBroadcastStats
+    final HashMap<String, BroadcastStats> mBroadcastStats
             = new HashMap<String, BroadcastStats>();
     
-    public AlarmManagerService(Context context) {
-        mContext = context;
+    @Override
+    public void onStart() {
         mNativeData = init();
         mNextWakeup = mNextNonWakeup = 0;
 
         // We have to set current TimeZone info to kernel
         // because kernel doesn't keep this after reboot
-        String tz = SystemProperties.get(TIMEZONE_PROPERTY);
-        if (tz != null) {
-            setTimeZone(tz);
-        }
+        setTimeZoneImpl(SystemProperties.get(TIMEZONE_PROPERTY));
 
-        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+        PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
         
-        mTimeTickSender = PendingIntent.getBroadcastAsUser(context, 0,
+        mTimeTickSender = PendingIntent.getBroadcastAsUser(getContext(), 0,
                 new Intent(Intent.ACTION_TIME_TICK).addFlags(
                         Intent.FLAG_RECEIVER_REGISTERED_ONLY
                         | Intent.FLAG_RECEIVER_FOREGROUND), 0,
                         UserHandle.ALL);
         Intent intent = new Intent(Intent.ACTION_DATE_CHANGED);
         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
-        mDateChangeSender = PendingIntent.getBroadcastAsUser(context, 0, intent,
+        mDateChangeSender = PendingIntent.getBroadcastAsUser(getContext(), 0, intent,
                 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT, UserHandle.ALL);
         
         // now that we have initied the driver schedule the alarm
-        mClockReceiver= new ClockReceiver();
+        mClockReceiver = new ClockReceiver();
         mClockReceiver.scheduleTimeTickEvent();
         mClockReceiver.scheduleDateChangedEvent();
         mUninstallReceiver = new UninstallReceiver();
         
         if (mNativeData != 0) {
-            mWaitThread.start();
+            AlarmThread waitThread = new AlarmThread();
+            waitThread.start();
         } else {
             Slog.w(TAG, "Failed to open alarm driver. Falling back to a handler.");
         }
+
+        publishBinderService(Context.ALARM_SERVICE, mService);
     }
-    
+
+    @Override
     protected void finalize() throws Throwable {
         try {
             close(mNativeData);
@@ -508,19 +507,51 @@
         }
     }
 
-    @Override
-    public void set(int type, long triggerAtTime, long windowLength, long interval,
-            PendingIntent operation, WorkSource workSource) {
-        if (workSource != null) {
-            mContext.enforceCallingPermission(
-                    android.Manifest.permission.UPDATE_DEVICE_STATS,
-                    "AlarmManager.set");
+    void setTimeZoneImpl(String tz) {
+        if (TextUtils.isEmpty(tz)) {
+            return;
         }
 
-        set(type, triggerAtTime, windowLength, interval, operation, false, workSource);
+        TimeZone zone = TimeZone.getTimeZone(tz);
+        // Prevent reentrant calls from stepping on each other when writing
+        // the time zone property
+        boolean timeZoneWasChanged = false;
+        synchronized (this) {
+            String current = SystemProperties.get(TIMEZONE_PROPERTY);
+            if (current == null || !current.equals(zone.getID())) {
+                if (localLOGV) {
+                    Slog.v(TAG, "timezone changed: " + current + ", new=" + zone.getID());
+                }
+                timeZoneWasChanged = true;
+                SystemProperties.set(TIMEZONE_PROPERTY, zone.getID());
+            }
+
+            // Update the kernel timezone information
+            // Kernel tracks time offsets as 'minutes west of GMT'
+            int gmtOffset = zone.getOffset(System.currentTimeMillis());
+            setKernelTimezone(mNativeData, -(gmtOffset / 60000));
+        }
+
+        TimeZone.setDefault(null);
+
+        if (timeZoneWasChanged) {
+            Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
+            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+            intent.putExtra("time-zone", zone.getID());
+            getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
+        }
     }
 
-    public void set(int type, long triggerAtTime, long windowLength, long interval,
+    void removeImpl(PendingIntent operation) {
+        if (operation == null) {
+            return;
+        }
+        synchronized (mLock) {
+            removeLocked(operation);
+        }
+    }
+
+    void setImpl(int type, long triggerAtTime, long windowLength, long interval,
             PendingIntent operation, boolean isStandalone, WorkSource workSource) {
         if (operation == null) {
             Slog.w(TAG, "set/setRepeating ignored because there is no intent");
@@ -606,231 +637,64 @@
         rescheduleKernelAlarmsLocked();
     }
 
-    private void logBatchesLocked() {
-        ByteArrayOutputStream bs = new ByteArrayOutputStream(2048);
-        PrintWriter pw = new PrintWriter(bs);
-        final long nowRTC = System.currentTimeMillis();
-        final long nowELAPSED = SystemClock.elapsedRealtime();
-        final int NZ = mAlarmBatches.size();
-        for (int iz = 0; iz < NZ; iz++) {
-            Batch bz = mAlarmBatches.get(iz);
-            pw.append("Batch "); pw.print(iz); pw.append(": "); pw.println(bz);
-            dumpAlarmList(pw, bz.alarms, "  ", nowELAPSED, nowRTC);
-            pw.flush();
-            Slog.v(TAG, bs.toString());
-            bs.reset();
-        }
-    }
-
-    private boolean validateConsistencyLocked() {
-        if (DEBUG_VALIDATE) {
-            long lastTime = Long.MIN_VALUE;
-            final int N = mAlarmBatches.size();
-            for (int i = 0; i < N; i++) {
-                Batch b = mAlarmBatches.get(i);
-                if (b.start >= lastTime) {
-                    // duplicate start times are okay because of standalone batches
-                    lastTime = b.start;
-                } else {
-                    Slog.e(TAG, "CONSISTENCY FAILURE: Batch " + i + " is out of order");
-                    logBatchesLocked();
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-
-    private Batch findFirstWakeupBatchLocked() {
-        final int N = mAlarmBatches.size();
-        for (int i = 0; i < N; i++) {
-            Batch b = mAlarmBatches.get(i);
-            if (b.hasWakeups()) {
-                return b;
-            }
-        }
-        return null;
-    }
-
-    private void rescheduleKernelAlarmsLocked() {
-        // Schedule the next upcoming wakeup alarm.  If there is a deliverable batch
-        // prior to that which contains no wakeups, we schedule that as well.
-        if (mAlarmBatches.size() > 0) {
-            final Batch firstWakeup = findFirstWakeupBatchLocked();
-            final Batch firstBatch = mAlarmBatches.get(0);
-            if (firstWakeup != null && mNextWakeup != firstWakeup.start) {
-                mNextWakeup = firstWakeup.start;
-                setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);
-            }
-            if (firstBatch != firstWakeup && mNextNonWakeup != firstBatch.start) {
-                mNextNonWakeup = firstBatch.start;
-                setLocked(ELAPSED_REALTIME, firstBatch.start);
-            }
-        }
-    }
-
-    public void setTime(long millis) {
-        mContext.enforceCallingOrSelfPermission(
-                "android.permission.SET_TIME",
-                "setTime");
-
-        SystemClock.setCurrentTimeMillis(millis);
-    }
-
-    public void setTimeZone(String tz) {
-        mContext.enforceCallingOrSelfPermission(
-                "android.permission.SET_TIME_ZONE",
-                "setTimeZone");
-
-        long oldId = Binder.clearCallingIdentity();
-        try {
-            if (TextUtils.isEmpty(tz)) return;
-            TimeZone zone = TimeZone.getTimeZone(tz);
-            // Prevent reentrant calls from stepping on each other when writing
-            // the time zone property
-            boolean timeZoneWasChanged = false;
-            synchronized (this) {
-                String current = SystemProperties.get(TIMEZONE_PROPERTY);
-                if (current == null || !current.equals(zone.getID())) {
-                    if (localLOGV) {
-                        Slog.v(TAG, "timezone changed: " + current + ", new=" + zone.getID());
-                    }
-                    timeZoneWasChanged = true;
-                    SystemProperties.set(TIMEZONE_PROPERTY, zone.getID());
-                }
-
-                // Update the kernel timezone information
-                // Kernel tracks time offsets as 'minutes west of GMT'
-                int gmtOffset = zone.getOffset(System.currentTimeMillis());
-                setKernelTimezone(mNativeData, -(gmtOffset / 60000));
+    private final IBinder mService = new IAlarmManager.Stub() {
+        @Override
+        public void set(int type, long triggerAtTime, long windowLength, long interval,
+                PendingIntent operation, WorkSource workSource) {
+            if (workSource != null) {
+                getContext().enforceCallingPermission(
+                        android.Manifest.permission.UPDATE_DEVICE_STATS,
+                        "AlarmManager.set");
             }
 
-            TimeZone.setDefault(null);
+            setImpl(type, triggerAtTime, windowLength, interval, operation,
+                    false, workSource);
+        }
 
-            if (timeZoneWasChanged) {
-                Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
-                intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
-                intent.putExtra("time-zone", zone.getID());
-                mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
-            }
-        } finally {
-            Binder.restoreCallingIdentity(oldId);
+        @Override
+        public void setTime(long millis) {
+            getContext().enforceCallingOrSelfPermission(
+                    "android.permission.SET_TIME",
+                    "setTime");
+
+            SystemClock.setCurrentTimeMillis(millis);
         }
-    }
-    
-    public void remove(PendingIntent operation) {
-        if (operation == null) {
-            return;
-        }
-        synchronized (mLock) {
-            removeLocked(operation);
-        }
-    }
-    
-    public void removeLocked(PendingIntent operation) {
-        boolean didRemove = false;
-        for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
-            Batch b = mAlarmBatches.get(i);
-            didRemove |= b.remove(operation);
-            if (b.size() == 0) {
-                mAlarmBatches.remove(i);
+
+        @Override
+        public void setTimeZone(String tz) {
+            getContext().enforceCallingOrSelfPermission(
+                    "android.permission.SET_TIME_ZONE",
+                    "setTimeZone");
+
+            final long oldId = Binder.clearCallingIdentity();
+            try {
+                setTimeZoneImpl(tz);
+            } finally {
+                Binder.restoreCallingIdentity(oldId);
             }
         }
 
-        if (didRemove) {
-            if (DEBUG_BATCH) {
-                Slog.v(TAG, "remove(operation) changed bounds; rebatching");
-            }
-            rebatchAllAlarmsLocked(true);
-            rescheduleKernelAlarmsLocked();
-        }
-    }
+        @Override
+        public void remove(PendingIntent operation) {
+            removeImpl(operation);
 
-    public void removeLocked(String packageName) {
-        boolean didRemove = false;
-        for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
-            Batch b = mAlarmBatches.get(i);
-            didRemove |= b.remove(packageName);
-            if (b.size() == 0) {
-                mAlarmBatches.remove(i);
-            }
         }
 
-        if (didRemove) {
-            if (DEBUG_BATCH) {
-                Slog.v(TAG, "remove(package) changed bounds; rebatching");
+        @Override
+        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                    != PackageManager.PERMISSION_GRANTED) {
+                pw.println("Permission Denial: can't dump AlarmManager from from pid="
+                        + Binder.getCallingPid()
+                        + ", uid=" + Binder.getCallingUid());
+                return;
             }
-            rebatchAllAlarmsLocked(true);
-            rescheduleKernelAlarmsLocked();
-        }
-    }
 
-    public void removeUserLocked(int userHandle) {
-        boolean didRemove = false;
-        for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
-            Batch b = mAlarmBatches.get(i);
-            didRemove |= b.remove(userHandle);
-            if (b.size() == 0) {
-                mAlarmBatches.remove(i);
-            }
+            dumpImpl(pw);
         }
+    };
 
-        if (didRemove) {
-            if (DEBUG_BATCH) {
-                Slog.v(TAG, "remove(user) changed bounds; rebatching");
-            }
-            rebatchAllAlarmsLocked(true);
-            rescheduleKernelAlarmsLocked();
-        }
-    }
-
-    public boolean lookForPackageLocked(String packageName) {
-        for (int i = 0; i < mAlarmBatches.size(); i++) {
-            Batch b = mAlarmBatches.get(i);
-            if (b.hasPackage(packageName)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private void setLocked(int type, long when)
-    {
-        if (mNativeData != 0)
-        {
-            // The kernel never triggers alarms with negative wakeup times
-            // so we ensure they are positive.
-            long alarmSeconds, alarmNanoseconds;
-            if (when < 0) {
-                alarmSeconds = 0;
-                alarmNanoseconds = 0;
-            } else {
-                alarmSeconds = when / 1000;
-                alarmNanoseconds = (when % 1000) * 1000 * 1000;
-            }
-            
-            set(mNativeData, type, alarmSeconds, alarmNanoseconds);
-        }
-        else
-        {
-            Message msg = Message.obtain();
-            msg.what = ALARM_EVENT;
-            
-            mHandler.removeMessages(ALARM_EVENT);
-            mHandler.sendMessageAtTime(msg, when);
-        }
-    }
-    
-    @Override
-    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
-                != PackageManager.PERMISSION_GRANTED) {
-            pw.println("Permission Denial: can't dump AlarmManager from from pid="
-                    + Binder.getCallingPid()
-                    + ", uid=" + Binder.getCallingUid());
-            return;
-        }
-        
+    void dumpImpl(PrintWriter pw) {
         synchronized (mLock) {
             pw.println("Current Alarm Manager state:");
             final long nowRTC = System.currentTimeMillis();
@@ -980,6 +844,159 @@
         }
     }
 
+    private void logBatchesLocked() {
+        ByteArrayOutputStream bs = new ByteArrayOutputStream(2048);
+        PrintWriter pw = new PrintWriter(bs);
+        final long nowRTC = System.currentTimeMillis();
+        final long nowELAPSED = SystemClock.elapsedRealtime();
+        final int NZ = mAlarmBatches.size();
+        for (int iz = 0; iz < NZ; iz++) {
+            Batch bz = mAlarmBatches.get(iz);
+            pw.append("Batch "); pw.print(iz); pw.append(": "); pw.println(bz);
+            dumpAlarmList(pw, bz.alarms, "  ", nowELAPSED, nowRTC);
+            pw.flush();
+            Slog.v(TAG, bs.toString());
+            bs.reset();
+        }
+    }
+
+    private boolean validateConsistencyLocked() {
+        if (DEBUG_VALIDATE) {
+            long lastTime = Long.MIN_VALUE;
+            final int N = mAlarmBatches.size();
+            for (int i = 0; i < N; i++) {
+                Batch b = mAlarmBatches.get(i);
+                if (b.start >= lastTime) {
+                    // duplicate start times are okay because of standalone batches
+                    lastTime = b.start;
+                } else {
+                    Slog.e(TAG, "CONSISTENCY FAILURE: Batch " + i + " is out of order");
+                    logBatchesLocked();
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    private Batch findFirstWakeupBatchLocked() {
+        final int N = mAlarmBatches.size();
+        for (int i = 0; i < N; i++) {
+            Batch b = mAlarmBatches.get(i);
+            if (b.hasWakeups()) {
+                return b;
+            }
+        }
+        return null;
+    }
+
+    void rescheduleKernelAlarmsLocked() {
+        // Schedule the next upcoming wakeup alarm.  If there is a deliverable batch
+        // prior to that which contains no wakeups, we schedule that as well.
+        if (mAlarmBatches.size() > 0) {
+            final Batch firstWakeup = findFirstWakeupBatchLocked();
+            final Batch firstBatch = mAlarmBatches.get(0);
+            if (firstWakeup != null && mNextWakeup != firstWakeup.start) {
+                mNextWakeup = firstWakeup.start;
+                setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);
+            }
+            if (firstBatch != firstWakeup && mNextNonWakeup != firstBatch.start) {
+                mNextNonWakeup = firstBatch.start;
+                setLocked(ELAPSED_REALTIME, firstBatch.start);
+            }
+        }
+    }
+
+    private void removeLocked(PendingIntent operation) {
+        boolean didRemove = false;
+        for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
+            Batch b = mAlarmBatches.get(i);
+            didRemove |= b.remove(operation);
+            if (b.size() == 0) {
+                mAlarmBatches.remove(i);
+            }
+        }
+
+        if (didRemove) {
+            if (DEBUG_BATCH) {
+                Slog.v(TAG, "remove(operation) changed bounds; rebatching");
+            }
+            rebatchAllAlarmsLocked(true);
+            rescheduleKernelAlarmsLocked();
+        }
+    }
+
+    void removeLocked(String packageName) {
+        boolean didRemove = false;
+        for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
+            Batch b = mAlarmBatches.get(i);
+            didRemove |= b.remove(packageName);
+            if (b.size() == 0) {
+                mAlarmBatches.remove(i);
+            }
+        }
+
+        if (didRemove) {
+            if (DEBUG_BATCH) {
+                Slog.v(TAG, "remove(package) changed bounds; rebatching");
+            }
+            rebatchAllAlarmsLocked(true);
+            rescheduleKernelAlarmsLocked();
+        }
+    }
+
+    void removeUserLocked(int userHandle) {
+        boolean didRemove = false;
+        for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
+            Batch b = mAlarmBatches.get(i);
+            didRemove |= b.remove(userHandle);
+            if (b.size() == 0) {
+                mAlarmBatches.remove(i);
+            }
+        }
+
+        if (didRemove) {
+            if (DEBUG_BATCH) {
+                Slog.v(TAG, "remove(user) changed bounds; rebatching");
+            }
+            rebatchAllAlarmsLocked(true);
+            rescheduleKernelAlarmsLocked();
+        }
+    }
+
+    boolean lookForPackageLocked(String packageName) {
+        for (int i = 0; i < mAlarmBatches.size(); i++) {
+            Batch b = mAlarmBatches.get(i);
+            if (b.hasPackage(packageName)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void setLocked(int type, long when) {
+        if (mNativeData != 0) {
+            // The kernel never triggers alarms with negative wakeup times
+            // so we ensure they are positive.
+            long alarmSeconds, alarmNanoseconds;
+            if (when < 0) {
+                alarmSeconds = 0;
+                alarmNanoseconds = 0;
+            } else {
+                alarmSeconds = when / 1000;
+                alarmNanoseconds = (when % 1000) * 1000 * 1000;
+            }
+            
+            set(mNativeData, type, alarmSeconds, alarmNanoseconds);
+        } else {
+            Message msg = Message.obtain();
+            msg.what = ALARM_EVENT;
+            
+            mHandler.removeMessages(ALARM_EVENT);
+            mHandler.sendMessageAtTime(msg, when);
+        }
+    }
+
     private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list,
             String prefix, String label, long now) {
         for (int i=list.size()-1; i>=0; i--) {
@@ -1020,7 +1037,7 @@
     private native int waitForAlarm(long nativeData);
     private native int setKernelTimezone(long nativeData, int minuteswest);
 
-    private void triggerAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED, long nowRTC) {
+    void triggerAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED, long nowRTC) {
         // batches are temporally sorted, so we need only pull from the
         // start of the list until we either empty it or hit a batch
         // that is not yet deliverable
@@ -1166,13 +1183,13 @@
                     if (DEBUG_BATCH) {
                         Slog.v(TAG, "Time changed notification from kernel; rebatching");
                     }
-                    remove(mTimeTickSender);
+                    removeImpl(mTimeTickSender);
                     rebatchAllAlarms();
                     mClockReceiver.scheduleTimeTickEvent();
                     Intent intent = new Intent(Intent.ACTION_TIME_CHANGED);
                     intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
                             | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-                    mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+                    getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
                 }
                 
                 synchronized (mLock) {
@@ -1206,7 +1223,7 @@
                         Alarm alarm = triggerList.get(i);
                         try {
                             if (localLOGV) Slog.v(TAG, "sending alarm " + alarm);
-                            alarm.operation.send(mContext, 0,
+                            alarm.operation.send(getContext(), 0,
                                     mBackgroundIntent.putExtra(
                                             Intent.EXTRA_ALARM_COUNT, alarm.count),
                                     mResultReceiver, mHandler);
@@ -1248,7 +1265,7 @@
                             if (alarm.repeatInterval > 0) {
                                 // This IntentSender is no longer valid, but this
                                 // is a repeating alarm, so toss the hoser.
-                                remove(alarm.operation);
+                                removeImpl(alarm.operation);
                             }
                         } catch (RuntimeException e) {
                             Slog.w(TAG, "Failure sending alarm.", e);
@@ -1310,7 +1327,7 @@
                         if (alarm.repeatInterval > 0) {
                             // This IntentSender is no longer valid, but this
                             // is a repeating alarm, so toss the hoser.
-                            remove(alarm.operation);
+                            removeImpl(alarm.operation);
                         }
                     }
                 }
@@ -1323,7 +1340,7 @@
             IntentFilter filter = new IntentFilter();
             filter.addAction(Intent.ACTION_TIME_TICK);
             filter.addAction(Intent.ACTION_DATE_CHANGED);
-            mContext.registerReceiver(this, filter);
+            getContext().registerReceiver(this, filter);
         }
         
         @Override
@@ -1354,7 +1371,7 @@
             final long tickEventDelay = nextTime - currentTime;
 
             final WorkSource workSource = null; // Let system take blame for time tick events.
-            set(ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay, 0,
+            setImpl(ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay, 0,
                     0, mTimeTickSender, true, workSource);
         }
 
@@ -1368,7 +1385,7 @@
             calendar.add(Calendar.DAY_OF_MONTH, 1);
 
             final WorkSource workSource = null; // Let system take blame for date change events.
-            set(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender, true, workSource);
+            setImpl(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender, true, workSource);
         }
     }
     
@@ -1379,12 +1396,12 @@
             filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
             filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
             filter.addDataScheme("package");
-            mContext.registerReceiver(this, filter);
+            getContext().registerReceiver(this, filter);
              // Register for events related to sdcard installation.
             IntentFilter sdFilter = new IntentFilter();
             sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
             sdFilter.addAction(Intent.ACTION_USER_STOPPED);
-            mContext.registerReceiver(this, sdFilter);
+            getContext().registerReceiver(this, sdFilter);
         }
         
         @Override
diff --git a/services/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
similarity index 100%
rename from services/java/com/android/server/AppOpsService.java
rename to services/core/java/com/android/server/AppOpsService.java
diff --git a/services/java/com/android/server/AssetAtlasService.java b/services/core/java/com/android/server/AssetAtlasService.java
similarity index 100%
rename from services/java/com/android/server/AssetAtlasService.java
rename to services/core/java/com/android/server/AssetAtlasService.java
diff --git a/services/java/com/android/server/AttributeCache.java b/services/core/java/com/android/server/AttributeCache.java
similarity index 100%
rename from services/java/com/android/server/AttributeCache.java
rename to services/core/java/com/android/server/AttributeCache.java
diff --git a/services/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
similarity index 97%
rename from services/java/com/android/server/BatteryService.java
rename to services/core/java/com/android/server/BatteryService.java
index 5f3f894..cc9055d 100644
--- a/services/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -19,6 +19,8 @@
 import android.os.BatteryStats;
 import com.android.internal.app.IBatteryStats;
 import com.android.server.am.BatteryStatsService;
+import com.android.server.lights.Light;
+import com.android.server.lights.LightsManager;
 
 import android.app.ActivityManagerNative;
 import android.content.ContentResolver;
@@ -134,13 +136,10 @@
 
     private boolean mSentLowBatteryBroadcast = false;
 
-    private BatteryListener mBatteryPropertiesListener;
-    private IBatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
-
-    public BatteryService(Context context, LightsService lights) {
+    public BatteryService(Context context, LightsManager lightsManager) {
         mContext = context;
         mHandler = new Handler(true /*async*/);
-        mLed = new Led(context, lights);
+        mLed = new Led(context, lightsManager);
         mBatteryStats = BatteryStatsService.getService();
 
         mCriticalBatteryLevel = mContext.getResources().getInteger(
@@ -158,13 +157,11 @@
                     "DEVPATH=/devices/virtual/switch/invalid_charger");
         }
 
-        mBatteryPropertiesListener = new BatteryListener();
-
         IBinder b = ServiceManager.getService("batterypropreg");
-        mBatteryPropertiesRegistrar = IBatteryPropertiesRegistrar.Stub.asInterface(b);
-
+        final IBatteryPropertiesRegistrar batteryPropertiesRegistrar =
+                IBatteryPropertiesRegistrar.Stub.asInterface(b);
         try {
-            mBatteryPropertiesRegistrar.registerListener(mBatteryPropertiesListener);
+            batteryPropertiesRegistrar.registerListener(new BatteryListener());
         } catch (RemoteException e) {
             // Should never happen.
         }
@@ -688,7 +685,7 @@
     };
 
     private final class Led {
-        private final LightsService.Light mBatteryLight;
+        private final Light mBatteryLight;
 
         private final int mBatteryLowARGB;
         private final int mBatteryMediumARGB;
@@ -696,8 +693,8 @@
         private final int mBatteryLedOn;
         private final int mBatteryLedOff;
 
-        public Led(Context context, LightsService lights) {
-            mBatteryLight = lights.getLight(LightsService.LIGHT_ID_BATTERY);
+        public Led(Context context, LightsManager lights) {
+            mBatteryLight = lights.getLight(LightsManager.LIGHT_ID_BATTERY);
 
             mBatteryLowARGB = context.getResources().getInteger(
                     com.android.internal.R.integer.config_notificationsBatteryLowARGB);
@@ -723,7 +720,7 @@
                     mBatteryLight.setColor(mBatteryLowARGB);
                 } else {
                     // Flash red when battery is low and not charging
-                    mBatteryLight.setFlashing(mBatteryLowARGB, LightsService.LIGHT_FLASH_TIMED,
+                    mBatteryLight.setFlashing(mBatteryLowARGB, Light.LIGHT_FLASH_TIMED,
                             mBatteryLedOn, mBatteryLedOff);
                 }
             } else if (status == BatteryManager.BATTERY_STATUS_CHARGING
@@ -743,8 +740,14 @@
     }
 
     private final class BatteryListener extends IBatteryPropertiesListener.Stub {
+        @Override
         public void batteryPropertiesChanged(BatteryProperties props) {
-            BatteryService.this.update(props);
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                BatteryService.this.update(props);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
        }
     }
 }
diff --git a/services/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
similarity index 100%
rename from services/java/com/android/server/BluetoothManagerService.java
rename to services/core/java/com/android/server/BluetoothManagerService.java
diff --git a/services/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java
similarity index 100%
rename from services/java/com/android/server/BootReceiver.java
rename to services/core/java/com/android/server/BootReceiver.java
diff --git a/services/java/com/android/server/BrickReceiver.java b/services/core/java/com/android/server/BrickReceiver.java
similarity index 100%
rename from services/java/com/android/server/BrickReceiver.java
rename to services/core/java/com/android/server/BrickReceiver.java
diff --git a/services/java/com/android/server/CertBlacklister.java b/services/core/java/com/android/server/CertBlacklister.java
similarity index 100%
rename from services/java/com/android/server/CertBlacklister.java
rename to services/core/java/com/android/server/CertBlacklister.java
diff --git a/services/java/com/android/server/CommonTimeManagementService.java b/services/core/java/com/android/server/CommonTimeManagementService.java
similarity index 100%
rename from services/java/com/android/server/CommonTimeManagementService.java
rename to services/core/java/com/android/server/CommonTimeManagementService.java
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
similarity index 100%
rename from services/java/com/android/server/ConnectivityService.java
rename to services/core/java/com/android/server/ConnectivityService.java
diff --git a/services/java/com/android/server/ConsumerIrService.java b/services/core/java/com/android/server/ConsumerIrService.java
similarity index 100%
rename from services/java/com/android/server/ConsumerIrService.java
rename to services/core/java/com/android/server/ConsumerIrService.java
diff --git a/services/java/com/android/server/CountryDetectorService.java b/services/core/java/com/android/server/CountryDetectorService.java
similarity index 100%
rename from services/java/com/android/server/CountryDetectorService.java
rename to services/core/java/com/android/server/CountryDetectorService.java
diff --git a/services/java/com/android/server/DiskStatsService.java b/services/core/java/com/android/server/DiskStatsService.java
similarity index 100%
rename from services/java/com/android/server/DiskStatsService.java
rename to services/core/java/com/android/server/DiskStatsService.java
diff --git a/services/java/com/android/server/DockObserver.java b/services/core/java/com/android/server/DockObserver.java
similarity index 100%
rename from services/java/com/android/server/DockObserver.java
rename to services/core/java/com/android/server/DockObserver.java
diff --git a/services/java/com/android/server/DropBoxManagerService.java b/services/core/java/com/android/server/DropBoxManagerService.java
similarity index 100%
rename from services/java/com/android/server/DropBoxManagerService.java
rename to services/core/java/com/android/server/DropBoxManagerService.java
diff --git a/services/java/com/android/server/EntropyMixer.java b/services/core/java/com/android/server/EntropyMixer.java
similarity index 100%
rename from services/java/com/android/server/EntropyMixer.java
rename to services/core/java/com/android/server/EntropyMixer.java
diff --git a/services/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
similarity index 100%
rename from services/java/com/android/server/EventLogTags.logtags
rename to services/core/java/com/android/server/EventLogTags.logtags
diff --git a/services/java/com/android/server/FgThread.java b/services/core/java/com/android/server/FgThread.java
similarity index 100%
rename from services/java/com/android/server/FgThread.java
rename to services/core/java/com/android/server/FgThread.java
diff --git a/services/java/com/android/server/INativeDaemonConnectorCallbacks.java b/services/core/java/com/android/server/INativeDaemonConnectorCallbacks.java
similarity index 100%
rename from services/java/com/android/server/INativeDaemonConnectorCallbacks.java
rename to services/core/java/com/android/server/INativeDaemonConnectorCallbacks.java
diff --git a/services/java/com/android/server/IdleMaintenanceService.java b/services/core/java/com/android/server/IdleMaintenanceService.java
similarity index 100%
rename from services/java/com/android/server/IdleMaintenanceService.java
rename to services/core/java/com/android/server/IdleMaintenanceService.java
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
similarity index 99%
rename from services/java/com/android/server/InputMethodManagerService.java
rename to services/core/java/com/android/server/InputMethodManagerService.java
index a996dbd..26424a5 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -28,7 +28,7 @@
 import com.android.internal.view.IInputMethodManager;
 import com.android.internal.view.IInputMethodSession;
 import com.android.internal.view.InputBindResult;
-import com.android.server.EventLogTags;
+import com.android.server.statusbar.StatusBarManagerService;
 import com.android.server.wm.WindowManagerService;
 
 import org.xmlpull.v1.XmlPullParser;
diff --git a/services/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java
similarity index 100%
rename from services/java/com/android/server/IntentResolver.java
rename to services/core/java/com/android/server/IntentResolver.java
diff --git a/services/java/com/android/server/IoThread.java b/services/core/java/com/android/server/IoThread.java
similarity index 100%
rename from services/java/com/android/server/IoThread.java
rename to services/core/java/com/android/server/IoThread.java
diff --git a/services/core/java/com/android/server/LocalServices.java b/services/core/java/com/android/server/LocalServices.java
new file mode 100644
index 0000000..deff79dc
--- /dev/null
+++ b/services/core/java/com/android/server/LocalServices.java
@@ -0,0 +1,58 @@
+/*
+ * 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.util.ArrayMap;
+
+/**
+ * This class is used in a similar way as ServiceManager, except the services registered here
+ * are not Binder objects and are only available in the same process.
+ *
+ * Once all services are converted to the SystemService interface, this class can be absorbed
+ * into SystemServiceManager.
+ */
+public final class LocalServices {
+    private LocalServices() {}
+
+    private static final ArrayMap<Class<?>, Object> sLocalServiceObjects =
+            new ArrayMap<Class<?>, Object>();
+
+    /**
+     * Returns a local service instance that implements the specified interface.
+     *
+     * @param type The type of service.
+     * @return The service object.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T getService(Class<T> type) {
+        synchronized (sLocalServiceObjects) {
+            return (T) sLocalServiceObjects.get(type);
+        }
+    }
+
+    /**
+     * Adds a service instance of the specified interface to the global registry of local services.
+     */
+    public static <T> void addService(Class<T> type, T service) {
+        synchronized (sLocalServiceObjects) {
+            if (sLocalServiceObjects.containsKey(type)) {
+                throw new IllegalStateException("Overriding service registration");
+            }
+            sLocalServiceObjects.put(type, service);
+        }
+    }
+}
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
similarity index 100%
rename from services/java/com/android/server/LocationManagerService.java
rename to services/core/java/com/android/server/LocationManagerService.java
diff --git a/services/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
similarity index 100%
rename from services/java/com/android/server/LockSettingsService.java
rename to services/core/java/com/android/server/LockSettingsService.java
diff --git a/services/java/com/android/server/MasterClearReceiver.java b/services/core/java/com/android/server/MasterClearReceiver.java
similarity index 100%
rename from services/java/com/android/server/MasterClearReceiver.java
rename to services/core/java/com/android/server/MasterClearReceiver.java
diff --git a/services/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
similarity index 100%
rename from services/java/com/android/server/MountService.java
rename to services/core/java/com/android/server/MountService.java
diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java
similarity index 100%
rename from services/java/com/android/server/NativeDaemonConnector.java
rename to services/core/java/com/android/server/NativeDaemonConnector.java
diff --git a/services/java/com/android/server/NativeDaemonConnectorException.java b/services/core/java/com/android/server/NativeDaemonConnectorException.java
similarity index 100%
rename from services/java/com/android/server/NativeDaemonConnectorException.java
rename to services/core/java/com/android/server/NativeDaemonConnectorException.java
diff --git a/services/java/com/android/server/NativeDaemonEvent.java b/services/core/java/com/android/server/NativeDaemonEvent.java
similarity index 100%
rename from services/java/com/android/server/NativeDaemonEvent.java
rename to services/core/java/com/android/server/NativeDaemonEvent.java
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
similarity index 100%
rename from services/java/com/android/server/NetworkManagementService.java
rename to services/core/java/com/android/server/NetworkManagementService.java
diff --git a/services/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java
similarity index 100%
rename from services/java/com/android/server/NetworkTimeUpdateService.java
rename to services/core/java/com/android/server/NetworkTimeUpdateService.java
diff --git a/services/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
similarity index 100%
rename from services/java/com/android/server/NsdService.java
rename to services/core/java/com/android/server/NsdService.java
diff --git a/services/java/com/android/server/RandomBlock.java b/services/core/java/com/android/server/RandomBlock.java
similarity index 100%
rename from services/java/com/android/server/RandomBlock.java
rename to services/core/java/com/android/server/RandomBlock.java
diff --git a/services/java/com/android/server/RecognitionManagerService.java b/services/core/java/com/android/server/RecognitionManagerService.java
similarity index 100%
rename from services/java/com/android/server/RecognitionManagerService.java
rename to services/core/java/com/android/server/RecognitionManagerService.java
diff --git a/services/java/com/android/server/SamplingProfilerService.java b/services/core/java/com/android/server/SamplingProfilerService.java
similarity index 100%
rename from services/java/com/android/server/SamplingProfilerService.java
rename to services/core/java/com/android/server/SamplingProfilerService.java
diff --git a/services/java/com/android/server/SerialService.java b/services/core/java/com/android/server/SerialService.java
similarity index 100%
rename from services/java/com/android/server/SerialService.java
rename to services/core/java/com/android/server/SerialService.java
diff --git a/services/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
similarity index 100%
rename from services/java/com/android/server/ServiceWatcher.java
rename to services/core/java/com/android/server/ServiceWatcher.java
diff --git a/services/java/com/android/server/ShutdownActivity.java b/services/core/java/com/android/server/ShutdownActivity.java
similarity index 100%
rename from services/java/com/android/server/ShutdownActivity.java
rename to services/core/java/com/android/server/ShutdownActivity.java
diff --git a/services/java/com/android/server/SystemServer.java b/services/core/java/com/android/server/SystemServer.java
similarity index 90%
rename from services/java/com/android/server/SystemServer.java
rename to services/core/java/com/android/server/SystemServer.java
index a42cbcf..9ce41b2 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/core/java/com/android/server/SystemServer.java
@@ -17,6 +17,8 @@
 package com.android.server;
 
 import android.app.ActivityManagerNative;
+import android.app.IAlarmManager;
+import android.app.INotificationManager;
 import android.bluetooth.BluetoothAdapter;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -30,6 +32,7 @@
 import android.os.Environment;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -51,22 +54,30 @@
 import com.android.server.accounts.AccountManagerService;
 import com.android.server.am.ActivityManagerService;
 import com.android.server.am.BatteryStatsService;
+import com.android.server.clipboard.ClipboardService;
 import com.android.server.content.ContentService;
 import com.android.server.display.DisplayManagerService;
 import com.android.server.dreams.DreamManagerService;
 import com.android.server.input.InputManagerService;
+import com.android.server.lights.LightsManager;
+import com.android.server.lights.LightsService;
 import com.android.server.media.MediaRouterService;
 import com.android.server.net.NetworkPolicyManagerService;
 import com.android.server.net.NetworkStatsService;
+import com.android.server.notification.NotificationManagerService;
 import com.android.server.os.SchedulingPolicyService;
 import com.android.server.pm.Installer;
 import com.android.server.pm.PackageManagerService;
 import com.android.server.pm.UserManagerService;
 import com.android.server.power.PowerManagerService;
 import com.android.server.power.ShutdownThread;
-import com.android.server.print.PrintManagerService;
 import com.android.server.search.SearchManagerService;
+import com.android.server.statusbar.StatusBarManagerService;
+import com.android.server.storage.DeviceStorageMonitorService;
+import com.android.server.twilight.TwilightManager;
+import com.android.server.twilight.TwilightService;
 import com.android.server.usb.UsbService;
+import com.android.server.wallpaper.WallpaperManagerService;
 import com.android.server.wifi.WifiService;
 import com.android.server.wm.WindowManagerService;
 
@@ -84,6 +95,19 @@
 
     ContentResolver mContentResolver;
 
+    /*
+     * Implementation class names. TODO: Move them to a codegen class or load
+     * them from the build system somehow.
+     */
+    private static final String BACKUP_MANAGER_SERVICE_CLASS =
+            "com.android.server.backup.BackupManagerSystemService";
+    private static final String DEVICE_POLICY_MANAGER_SERVICE_CLASS =
+            "com.android.server.devicepolicy.DevicePolicyManagerSystemService";
+    private static final String APPWIDGET_SERVICE_CLASS =
+            "com.android.server.appwidget.AppWidgetService";
+    private static final String PRINT_MANAGER_SERVICE_CLASS =
+            "com.android.server.print.PrintManagerService";
+
     void reportWtf(String msg, Throwable e) {
         Slog.w(TAG, "***********************************************");
         Log.wtf(TAG, "BOOT FAILURE " + msg, e);
@@ -122,17 +146,16 @@
         String factoryTestStr = SystemProperties.get("ro.factorytest");
         int factoryTest = "".equals(factoryTestStr) ? SystemServer.FACTORY_TEST_OFF
                 : Integer.parseInt(factoryTestStr);
-        final boolean headless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
 
         Installer installer = null;
         AccountManagerService accountManager = null;
         ContentService contentService = null;
-        LightsService lights = null;
+        LightsManager lights = null;
         PowerManagerService power = null;
         DisplayManagerService display = null;
         BatteryService battery = null;
         VibratorService vibrator = null;
-        AlarmManagerService alarm = null;
+        IAlarmManager alarm = null;
         MountService mountService = null;
         NetworkManagementService networkManagement = null;
         NetworkStatsService networkStats = null;
@@ -148,8 +171,7 @@
         DockObserver dock = null;
         UsbService usb = null;
         SerialService serial = null;
-        TwilightService twilight = null;
-        UiModeManagerService uiMode = null;
+        TwilightManager twilight = null;
         RecognitionManagerService recognition = null;
         NetworkTimeUpdateService networkTimeUpdater = null;
         CommonTimeManagementService commonTimeMgmtService = null;
@@ -199,6 +221,8 @@
             Slog.e("System", "************ Failure starting bootstrap service", e);
         }
 
+        final SystemServiceManager systemServiceManager = new SystemServiceManager(context);
+
         boolean disableStorage = SystemProperties.getBoolean("config.disable_storage", false);
         boolean disableMedia = SystemProperties.getBoolean("config.disable_media", false);
         boolean disableBluetooth = SystemProperties.getBoolean("config.disable_bluetooth", false);
@@ -274,8 +298,8 @@
             Slog.i(TAG, "System Content Providers");
             ActivityManagerService.installSystemProviders();
 
-            Slog.i(TAG, "Lights Service");
-            lights = new LightsService(context);
+            systemServiceManager.startService(LightsService.class);
+            lights = LocalServices.getService(LightsManager.class);
 
             Slog.i(TAG, "Battery Service");
             battery = new BatteryService(context, lights);
@@ -291,17 +315,16 @@
 
             // only initialize the power service after we have started the
             // lights service, content providers and the battery service.
-            power.init(context, lights, ActivityManagerService.self(), battery,
+            power.init(context, lights, battery,
                     BatteryStatsService.getService(),
                     ActivityManagerService.self().getAppOpsService(), display);
 
-            Slog.i(TAG, "Alarm Manager");
-            alarm = new AlarmManagerService(context);
-            ServiceManager.addService(Context.ALARM_SERVICE, alarm);
+            systemServiceManager.startService(AlarmManagerService.class);
+            alarm = IAlarmManager.Stub.asInterface(
+                    ServiceManager.getService(Context.ALARM_SERVICE));
 
             Slog.i(TAG, "Init Watchdog");
-            Watchdog.getInstance().init(context, battery, power, alarm,
-                    ActivityManagerService.self());
+            Watchdog.getInstance().init(context, ActivityManagerService.self());
             Watchdog.getInstance().addThread(wmHandler, "WindowManager thread");
 
             Slog.i(TAG, "Input Manager");
@@ -344,11 +367,9 @@
             Slog.e("System", "************ Failure starting core service", e);
         }
 
-        DevicePolicyManagerService devicePolicy = null;
         StatusBarManagerService statusBar = null;
+        INotificationManager notification = null;
         InputMethodManagerService imm = null;
-        AppWidgetService appWidget = null;
-        NotificationManagerService notification = null;
         WallpaperManagerService wallpaper = null;
         LocationManagerService location = null;
         CountryDetectorService countryDetector = null;
@@ -356,7 +377,6 @@
         LockSettingsService lockSettings = null;
         DreamManagerService dreamy = null;
         AssetAtlasService atlas = null;
-        PrintManagerService printManager = null;
         MediaRouterService mediaRouter = null;
 
         // Bring up services needed for UI.
@@ -397,7 +417,7 @@
             ActivityManagerNative.getDefault().showBootMessage(
                     context.getResources().getText(
                             com.android.internal.R.string.android_upgrading_starting_apps),
-                            false);
+                    false);
         } catch (RemoteException e) {
         }
 
@@ -428,8 +448,7 @@
 
                 try {
                     Slog.i(TAG, "Device Policy");
-                    devicePolicy = new DevicePolicyManagerService(context);
-                    ServiceManager.addService(Context.DEVICE_POLICY_SERVICE, devicePolicy);
+                    systemServiceManager.startService(DEVICE_POLICY_MANAGER_SERVICE_CLASS);
                 } catch (Throwable e) {
                     reportWtf("starting DevicePolicyService", e);
                 }
@@ -567,22 +586,12 @@
                 reportWtf("making Content Service ready", e);
             }
 
-            try {
-                Slog.i(TAG, "Notification Manager");
-                notification = new NotificationManagerService(context, statusBar, lights);
-                ServiceManager.addService(Context.NOTIFICATION_SERVICE, notification);
-                networkPolicy.bindNotificationManager(notification);
-            } catch (Throwable e) {
-                reportWtf("starting Notification Manager", e);
-            }
+            systemServiceManager.startService(NotificationManagerService.class);
+            notification = INotificationManager.Stub.asInterface(
+                    ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+            networkPolicy.bindNotificationManager(notification);
 
-            try {
-                Slog.i(TAG, "Device Storage Monitor");
-                ServiceManager.addService(DeviceStorageMonitorService.SERVICE,
-                        new DeviceStorageMonitorService(context));
-            } catch (Throwable e) {
-                reportWtf("starting DeviceStorageMonitor service", e);
-            }
+            systemServiceManager.startService(DeviceStorageMonitorService.class);
 
             if (!disableLocation) {
                 try {
@@ -624,10 +633,8 @@
                         R.bool.config_enableWallpaperService)) {
                 try {
                     Slog.i(TAG, "Wallpaper Service");
-                    if (!headless) {
-                        wallpaper = new WallpaperManagerService(context);
-                        ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper);
-                    }
+                    wallpaper = new WallpaperManagerService(context);
+                    ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper);
                 } catch (Throwable e) {
                     reportWtf("starting Wallpaper Service", e);
                 }
@@ -683,34 +690,22 @@
                 }
             }
 
-            try {
-                Slog.i(TAG, "Twilight Service");
-                twilight = new TwilightService(context);
-            } catch (Throwable e) {
-                reportWtf("starting TwilightService", e);
-            }
+            systemServiceManager.startService(TwilightService.class);
+            twilight = LocalServices.getService(TwilightManager.class);
 
-            try {
-                Slog.i(TAG, "UI Mode Manager Service");
-                // Listen for UI mode changes
-                uiMode = new UiModeManagerService(context, twilight);
-            } catch (Throwable e) {
-                reportWtf("starting UiModeManagerService", e);
-            }
+            systemServiceManager.startService(UiModeManagerService.class);
 
             if (!disableNonCoreServices) {
                 try {
                     Slog.i(TAG, "Backup Service");
-                    ServiceManager.addService(Context.BACKUP_SERVICE,
-                            new BackupManagerService(context));
+                    systemServiceManager.startService(BACKUP_MANAGER_SERVICE_CLASS);
                 } catch (Throwable e) {
                     Slog.e(TAG, "Failure starting Backup Service", e);
                 }
 
                 try {
                     Slog.i(TAG, "AppWidget Service");
-                    appWidget = new AppWidgetService(context);
-                    ServiceManager.addService(Context.APPWIDGET_SERVICE, appWidget);
+                    systemServiceManager.startService(APPWIDGET_SERVICE_CLASS);
                 } catch (Throwable e) {
                     reportWtf("starting AppWidget Service", e);
                 }
@@ -801,8 +796,7 @@
 
             try {
                 Slog.i(TAG, "Print Service");
-                printManager = new PrintManagerService(context);
-                ServiceManager.addService(Context.PRINT_SERVICE, printManager);
+                systemServiceManager.startService(PRINT_MANAGER_SERVICE_CLASS);
             } catch (Throwable e) {
                 reportWtf("starting Print Service", e);
             }
@@ -848,21 +842,10 @@
             }
         }
 
-        if (devicePolicy != null) {
-            try {
-                devicePolicy.systemReady();
-            } catch (Throwable e) {
-                reportWtf("making Device Policy Service ready", e);
-            }
-        }
+        // Needed by DevicePolicyManager for initialization
+        systemServiceManager.startBootPhase(SystemService.PHASE_LOCK_SETTINGS_READY);
 
-        if (notification != null) {
-            try {
-                notification.systemReady();
-            } catch (Throwable e) {
-                reportWtf("making Notification Service ready", e);
-            }
-        }
+        systemServiceManager.startBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
 
         try {
             wm.systemReady();
@@ -911,9 +894,6 @@
         final ConnectivityService connectivityF = connectivity;
         final DockObserver dockF = dock;
         final UsbService usbF = usb;
-        final TwilightService twilightF = twilight;
-        final UiModeManagerService uiModeF = uiMode;
-        final AppWidgetService appWidgetF = appWidget;
         final WallpaperManagerService wallpaperF = wallpaper;
         final InputMethodManagerService immF = imm;
         final RecognitionManagerService recognitionF = recognition;
@@ -927,7 +907,6 @@
         final AssetAtlasService atlasF = atlas;
         final InputManagerService inputManagerF = inputManager;
         final TelephonyRegistry telephonyRegistryF = telephonyRegistry;
-        final PrintManagerService printManagerF = printManager;
         final MediaRouterService mediaRouterF = mediaRouter;
 
         // We now tell the activity manager it is okay to run third party
@@ -944,8 +923,10 @@
                 } catch (Throwable e) {
                     reportWtf("observing native crashes", e);
                 }
-                if (!headless) {
+                try {
                     startSystemUi(contextF);
+                } catch (Throwable e) {
+                    reportWtf("starting System UI", e);
                 }
                 try {
                     if (mountServiceF != null) mountServiceF.systemReady();
@@ -988,16 +969,6 @@
                     reportWtf("making USB Service ready", e);
                 }
                 try {
-                    if (twilightF != null) twilightF.systemReady();
-                } catch (Throwable e) {
-                    reportWtf("makin Twilight Service ready", e);
-                }
-                try {
-                    if (uiModeF != null) uiModeF.systemReady();
-                } catch (Throwable e) {
-                    reportWtf("making UI Mode Service ready", e);
-                }
-                try {
                     if (recognitionF != null) recognitionF.systemReady();
                 } catch (Throwable e) {
                     reportWtf("making Recognition Service ready", e);
@@ -1006,13 +977,9 @@
 
                 // It is now okay to let the various system services start their
                 // third party code...
+                systemServiceManager.startBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
 
                 try {
-                    if (appWidgetF != null) appWidgetF.systemRunning(safeMode);
-                } catch (Throwable e) {
-                    reportWtf("Notifying AppWidgetService running", e);
-                }
-                try {
                     if (wallpaperF != null) wallpaperF.systemRunning();
                 } catch (Throwable e) {
                     reportWtf("Notifying WallpaperService running", e);
@@ -1072,16 +1039,12 @@
                 }
 
                 try {
-                    if (printManagerF != null) printManagerF.systemRuning();
-                } catch (Throwable e) {
-                    reportWtf("Notifying PrintManagerService running", e);
-                }
-
-                try {
                     if (mediaRouterF != null) mediaRouterF.systemRunning();
                 } catch (Throwable e) {
                     reportWtf("Notifying MediaRouterService running", e);
                 }
+
+                systemServiceManager.startBootPhase(SystemService.PHASE_BOOT_COMPLETE);
             }
         });
 
diff --git a/services/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java
new file mode 100644
index 0000000..b9d30ce
--- /dev/null
+++ b/services/core/java/com/android/server/SystemService.java
@@ -0,0 +1,156 @@
+/*
+ * 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.content.Context;
+import android.os.IBinder;
+import android.os.ServiceManager;
+
+/**
+ * System services respond to lifecycle events that help the services know what
+ */
+public abstract class SystemService {
+    /*
+     * Boot Phases
+     */
+    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;
+    public static final int PHASE_BOOT_COMPLETE = 1000;
+
+    private SystemServiceManager mManager;
+    private Context mContext;
+
+    final void init(Context context, SystemServiceManager manager) {
+        mContext = context;
+        mManager = manager;
+        onCreate(context);
+    }
+
+    public final boolean isSafeMode() {
+        return mManager.isSafeMode();
+    }
+
+    /**
+     * Services are not yet available. This is a good place to do setup work that does
+     * not require other services.
+     *
+     * @param context The system context.
+     */
+    public void onCreate(Context context) {}
+
+    /**
+     * Called when the dependencies listed in the @Service class-annotation are available
+     * and after the chosen start phase.
+     * When this method returns, the service should be published.
+     */
+    public abstract void onStart();
+
+    /**
+     * Called on each phase of the boot process. Phases before the service's start phase
+     * (as defined in the @Service annotation) are never received.
+     *
+     * @param phase The current boot phase.
+     */
+    public void onBootPhase(int phase) {}
+
+    /**
+     * Publish the service so it is accessible to other services and apps.
+     */
+    protected final void publishBinderService(String name, IBinder service) {
+        ServiceManager.addService(name, service);
+    }
+
+    /**
+     * Get a binder service by its name.
+     */
+    protected final IBinder getBinderService(String name) {
+        return ServiceManager.getService(name);
+    }
+
+    /**
+     * Publish the service so it is only accessible to the system process.
+     */
+    protected final <T> void publishLocalService(Class<T> type, T service) {
+        LocalServices.addService(type, service);
+    }
+
+    /**
+     * Get a local service by interface.
+     */
+    protected final <T> T getLocalService(Class<T> type) {
+        return LocalServices.getService(type);
+    }
+
+    public final Context getContext() {
+        return mContext;
+    }
+
+//    /**
+//     * Called when a new user has been created. If your service deals with multiple users, this
+//     * method should be overridden.
+//     *
+//     * @param userHandle The user that was created.
+//     */
+//    public void onUserCreated(int userHandle) {
+//    }
+//
+//    /**
+//     * Called when an existing user has started a new session. If your service deals with multiple
+//     * users, this method should be overridden.
+//     *
+//     * @param userHandle The user who started a new session.
+//     */
+//    public void onUserStarted(int userHandle) {
+//    }
+//
+//    /**
+//     * Called when a background user session has entered the foreground. If your service deals with
+//     * multiple users, this method should be overridden.
+//     *
+//     * @param userHandle The user who's session entered the foreground.
+//     */
+//    public void onUserForeground(int userHandle) {
+//    }
+//
+//    /**
+//     * Called when a foreground user session has entered the background. If your service deals with
+//     * multiple users, this method should be overridden;
+//     *
+//     * @param userHandle The user who's session entered the background.
+//     */
+//    public void onUserBackground(int userHandle) {
+//    }
+//
+//    /**
+//     * Called when a user's active session has stopped. If your service deals with multiple users,
+//     * this method should be overridden.
+//     *
+//     * @param userHandle The user who's session has stopped.
+//     */
+//    public void onUserStopped(int userHandle) {
+//    }
+//
+//    /**
+//     * Called when a user has been removed from the system. If your service deals with multiple
+//     * users, this method should be overridden.
+//     *
+//     * @param userHandle The user who has been removed.
+//     */
+//    public void onUserRemoved(int userHandle) {
+//    }
+}
diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
new file mode 100644
index 0000000..59f7e92
--- /dev/null
+++ b/services/core/java/com/android/server/SystemServiceManager.java
@@ -0,0 +1,163 @@
+/*
+ * 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.content.Context;
+import android.util.Log;
+import android.util.Slog;
+
+import java.util.ArrayList;
+
+/**
+ * Manages creating, starting, and other lifecycle events of system services.
+ */
+public class SystemServiceManager {
+    private static final String TAG = "SystemServiceManager";
+
+    private final Context mContext;
+    private boolean mSafeMode;
+
+    // Services that should receive lifecycle events.
+    private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();
+
+    private int mCurrentPhase = -1;
+
+    public SystemServiceManager(Context context) {
+        mContext = context;
+    }
+
+    public void startService(String className) {
+        try {
+            startService(Class.forName(className));
+        } catch (ClassNotFoundException cnfe) {
+            Slog.i(TAG, className + " not available, ignoring.");
+        }
+    }
+
+    /**
+     * Creates and starts a system service. The class must be a subclass of
+     * {@link com.android.server.SystemService}.
+     *
+     * @param serviceClass A Java class that implements the SystemService interface.
+     * @throws RuntimeException if the service fails to start.
+     */
+    public void startService(Class<?> serviceClass) {
+        final SystemService serviceInstance = createInstance(serviceClass);
+        try {
+            Slog.i(TAG, "Creating " + serviceClass.getSimpleName());
+            serviceInstance.init(mContext, this);
+        } catch (Throwable e) {
+            throw new RuntimeException("Failed to create service " + serviceClass.getName(), e);
+        }
+
+        mServices.add(serviceInstance);
+
+        try {
+            Slog.i(TAG, "Starting " + serviceClass.getSimpleName());
+            serviceInstance.onStart();
+        } catch (Throwable e) {
+            throw new RuntimeException("Failed to start service " + serviceClass.getName(), e);
+        }
+    }
+
+    /**
+     * Starts the specified boot phase for all system services that have been started up to
+     * this point.
+     *
+     * @param phase The boot phase to start.
+     */
+    public void startBootPhase(final int phase) {
+        if (phase <= mCurrentPhase) {
+            throw new IllegalArgumentException("Next phase must be larger than previous");
+        }
+        mCurrentPhase = phase;
+
+        Slog.i(TAG, "Starting phase " + mCurrentPhase);
+
+        final int serviceLen = mServices.size();
+        for (int i = 0; i < serviceLen; i++) {
+            final SystemService service = mServices.get(i);
+            try {
+                service.onBootPhase(mCurrentPhase);
+            } catch (Throwable e) {
+                reportWtf("Service " + service.getClass().getName() +
+                        " threw an Exception processing boot phase " + mCurrentPhase, e);
+            }
+        }
+    }
+
+    /** Sets the safe mode flag for services to query. */
+    public void setSafeMode(boolean safeMode) {
+        mSafeMode = safeMode;
+    }
+
+    /**
+     * Returns whether we are booting into safe mode.
+     * @return safe mode flag
+     */
+    public boolean isSafeMode() {
+        return mSafeMode;
+    }
+
+    /**
+     * Outputs the state of this manager to the System log.
+     */
+    public void dump() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("Current phase: ").append(mCurrentPhase).append("\n");
+        builder.append("Services:\n");
+        final int startedLen = mServices.size();
+        for (int i = 0; i < startedLen; i++) {
+            final SystemService service = mServices.get(i);
+            builder.append("\t")
+                    .append(service.getClass().getSimpleName())
+                    .append("\n");
+        }
+
+        Slog.e(TAG, builder.toString());
+    }
+
+    private SystemService createInstance(Class<?> clazz) {
+        // Make sure it's a type we expect
+        if (!SystemService.class.isAssignableFrom(clazz)) {
+            reportWtf("Class " + clazz.getName() + " does not extend " +
+                    SystemService.class.getName());
+        }
+
+        try {
+            return (SystemService) clazz.newInstance();
+        } catch (InstantiationException e) {
+            reportWtf("Class " + clazz.getName() + " is abstract", e);
+        } catch (IllegalAccessException e) {
+            reportWtf("Class " + clazz.getName() +
+                    " must have a public no-arg constructor", e);
+        }
+        return null;
+    }
+
+    private static void reportWtf(String message) {
+        reportWtf(message, null);
+    }
+
+    private static void reportWtf(String message, Throwable e) {
+        Slog.i(TAG, "******************************");
+        Log.wtf(TAG, message, e);
+
+        // Make sure we die
+        throw new RuntimeException(message, e);
+    }
+}
diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
similarity index 100%
rename from services/java/com/android/server/TelephonyRegistry.java
rename to services/core/java/com/android/server/TelephonyRegistry.java
diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java
similarity index 100%
rename from services/java/com/android/server/TextServicesManagerService.java
rename to services/core/java/com/android/server/TextServicesManagerService.java
diff --git a/services/java/com/android/server/TwilightCalculator.java b/services/core/java/com/android/server/TwilightCalculator.java
similarity index 100%
rename from services/java/com/android/server/TwilightCalculator.java
rename to services/core/java/com/android/server/TwilightCalculator.java
diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
similarity index 76%
rename from services/java/com/android/server/UiModeManagerService.java
rename to services/core/java/com/android/server/UiModeManagerService.java
index 062be01..de912dc 100644
--- a/services/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -34,9 +34,9 @@
 import android.os.BatteryManager;
 import android.os.Binder;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.PowerManager;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.dreams.Sandman;
@@ -47,9 +47,11 @@
 
 import com.android.internal.R;
 import com.android.internal.app.DisableCarModeActivity;
-import com.android.server.TwilightService.TwilightState;
+import com.android.server.twilight.TwilightListener;
+import com.android.server.twilight.TwilightManager;
+import com.android.server.twilight.TwilightState;
 
-final class UiModeManagerService extends IUiModeManager.Stub {
+final class UiModeManagerService extends SystemService {
     private static final String TAG = UiModeManager.class.getSimpleName();
     private static final boolean LOG = false;
 
@@ -57,40 +59,36 @@
     private static final boolean ENABLE_LAUNCH_CAR_DOCK_APP = true;
     private static final boolean ENABLE_LAUNCH_DESK_DOCK_APP = true;
 
-    private final Context mContext;
-    private final TwilightService mTwilightService;
-    private final Handler mHandler = new Handler();
-
     final Object mLock = new Object();
-
     private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
-    private int mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
 
-    private int mNightMode = UiModeManager.MODE_NIGHT_NO;
+    private int mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+    int mNightMode = UiModeManager.MODE_NIGHT_NO;
+
     private boolean mCarModeEnabled = false;
     private boolean mCharging = false;
-    private final int mDefaultUiModeType;
-    private final boolean mCarModeKeepsScreenOn;
-    private final boolean mDeskModeKeepsScreenOn;
-    private final boolean mTelevision;
-
+    private int mDefaultUiModeType;
+    private boolean mCarModeKeepsScreenOn;
+    private boolean mDeskModeKeepsScreenOn;
+    private boolean mTelevision;
     private boolean mComputedNightMode;
-    private int mCurUiMode = 0;
+
+    int mCurUiMode = 0;
     private int mSetUiMode = 0;
-
     private boolean mHoldingConfiguration = false;
+
     private Configuration mConfiguration = new Configuration();
+    boolean mSystemReady;
 
-    private boolean mSystemReady;
+    private final Handler mHandler = new Handler();
 
+    private TwilightManager mTwilightManager;
     private NotificationManager mNotificationManager;
-
     private StatusBarManager mStatusBarManager;
 
-    private final PowerManager mPowerManager;
-    private final PowerManager.WakeLock mWakeLock;
+    private PowerManager.WakeLock mWakeLock;
 
-    static Intent buildHomeIntent(String category) {
+    private static Intent buildHomeIntent(String category) {
         Intent intent = new Intent(Intent.ACTION_MAIN);
         intent.addCategory(category);
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
@@ -142,28 +140,26 @@
         }
     };
 
-    private final TwilightService.TwilightListener mTwilightListener =
-            new TwilightService.TwilightListener() {
+    private final TwilightListener mTwilightListener = new TwilightListener() {
         @Override
         public void onTwilightStateChanged() {
             updateTwilight();
         }
     };
 
-    public UiModeManagerService(Context context, TwilightService twilight) {
-        mContext = context;
-        mTwilightService = twilight;
+    @Override
+    public void onStart() {
+        final Context context = getContext();
+        mTwilightManager = getLocalService(TwilightManager.class);
+        final PowerManager powerManager =
+                (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+        mWakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
 
-        ServiceManager.addService(Context.UI_MODE_SERVICE, this);
-
-        mContext.registerReceiver(mDockModeReceiver,
+        context.registerReceiver(mDockModeReceiver,
                 new IntentFilter(Intent.ACTION_DOCK_EVENT));
-        mContext.registerReceiver(mBatteryReceiver,
+        context.registerReceiver(mBatteryReceiver,
                 new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
 
-        mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
-        mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
-
         mConfiguration.setToDefaults();
 
         mDefaultUiModeType = context.getResources().getInteger(
@@ -175,101 +171,139 @@
         mTelevision = context.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_TELEVISION);
 
-        mNightMode = Settings.Secure.getInt(mContext.getContentResolver(),
+        mNightMode = Settings.Secure.getInt(context.getContentResolver(),
                 Settings.Secure.UI_NIGHT_MODE, UiModeManager.MODE_NIGHT_AUTO);
 
-        mTwilightService.registerListener(mTwilightListener, mHandler);
+        mTwilightManager.registerListener(mTwilightListener, mHandler);
+
+        publishBinderService(Context.UI_MODE_SERVICE, mService);
     }
 
-    @Override // Binder call
-    public void disableCarMode(int flags) {
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            synchronized (mLock) {
-                setCarModeLocked(false);
-                if (mSystemReady) {
-                    updateLocked(0, flags);
+    private final IBinder mService = new IUiModeManager.Stub() {
+        @Override
+        public void enableCarMode(int flags) {
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    setCarModeLocked(true);
+                    if (mSystemReady) {
+                        updateLocked(flags, 0);
+                    }
                 }
+            } finally {
+                Binder.restoreCallingIdentity(ident);
             }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
         }
-    }
 
-    @Override // Binder call
-    public void enableCarMode(int flags) {
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            synchronized (mLock) {
-                setCarModeLocked(true);
-                if (mSystemReady) {
-                    updateLocked(flags, 0);
+        @Override
+        public void disableCarMode(int flags) {
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    setCarModeLocked(false);
+                    if (mSystemReady) {
+                        updateLocked(0, flags);
+                    }
                 }
+            } finally {
+                Binder.restoreCallingIdentity(ident);
             }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    @Override // Binder call
-    public int getCurrentModeType() {
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            synchronized (mLock) {
-                return mCurUiMode & Configuration.UI_MODE_TYPE_MASK;
-            }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    @Override // Binder call
-    public void setNightMode(int mode) {
-        switch (mode) {
-            case UiModeManager.MODE_NIGHT_NO:
-            case UiModeManager.MODE_NIGHT_YES:
-            case UiModeManager.MODE_NIGHT_AUTO:
-                break;
-            default:
-                throw new IllegalArgumentException("Unknown mode: " + mode);
         }
 
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            synchronized (mLock) {
-                if (isDoingNightModeLocked() && mNightMode != mode) {
-                    Settings.Secure.putInt(mContext.getContentResolver(),
-                            Settings.Secure.UI_NIGHT_MODE, mode);
-                    mNightMode = mode;
-                    updateLocked(0, 0);
+        @Override
+        public int getCurrentModeType() {
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    return mCurUiMode & Configuration.UI_MODE_TYPE_MASK;
                 }
+            } finally {
+                Binder.restoreCallingIdentity(ident);
             }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
         }
-    }
 
-    @Override // Binder call
-    public int getNightMode() {
+        @Override
+        public void setNightMode(int mode) {
+            switch (mode) {
+                case UiModeManager.MODE_NIGHT_NO:
+                case UiModeManager.MODE_NIGHT_YES:
+                case UiModeManager.MODE_NIGHT_AUTO:
+                    break;
+                default:
+                    throw new IllegalArgumentException("Unknown mode: " + mode);
+            }
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    if (isDoingNightModeLocked() && mNightMode != mode) {
+                        Settings.Secure.putInt(getContext().getContentResolver(),
+                                Settings.Secure.UI_NIGHT_MODE, mode);
+                        mNightMode = mode;
+                        updateLocked(0, 0);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override
+        public int getNightMode() {
+            synchronized (mLock) {
+                return mNightMode;
+            }
+        }
+
+        @Override
+        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                    != PackageManager.PERMISSION_GRANTED) {
+
+                pw.println("Permission Denial: can't dump uimode service from from pid="
+                        + Binder.getCallingPid()
+                        + ", uid=" + Binder.getCallingUid());
+                return;
+            }
+
+            dumpImpl(pw);
+        }
+    };
+
+    void dumpImpl(PrintWriter pw) {
         synchronized (mLock) {
-            return mNightMode;
+            pw.println("Current UI Mode Service state:");
+            pw.print("  mDockState="); pw.print(mDockState);
+                    pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState);
+            pw.print("  mNightMode="); pw.print(mNightMode);
+                    pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled);
+                    pw.print(" mComputedNightMode="); pw.println(mComputedNightMode);
+            pw.print("  mCurUiMode=0x"); pw.print(Integer.toHexString(mCurUiMode));
+                    pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode));
+            pw.print("  mHoldingConfiguration="); pw.print(mHoldingConfiguration);
+                    pw.print(" mSystemReady="); pw.println(mSystemReady);
+            pw.print("  mTwilightService.getCurrentState()=");
+                    pw.println(mTwilightManager.getCurrentState());
         }
     }
 
-    void systemReady() {
-        synchronized (mLock) {
-            mSystemReady = true;
-            mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR;
-            updateComputedNightModeLocked();
-            updateLocked(0, 0);
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+            synchronized (mLock) {
+                mSystemReady = true;
+                mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR;
+                updateComputedNightModeLocked();
+                updateLocked(0, 0);
+            }
         }
     }
 
-    private boolean isDoingNightModeLocked() {
+    boolean isDoingNightModeLocked() {
         return mCarModeEnabled || mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED;
     }
 
-    private void setCarModeLocked(boolean enabled) {
+    void setCarModeLocked(boolean enabled) {
         if (mCarModeEnabled != enabled) {
             mCarModeEnabled = enabled;
         }
@@ -344,7 +378,7 @@
         }
     }
 
-    private void updateLocked(int enableFlags, int disableFlags) {
+    void updateLocked(int enableFlags, int disableFlags) {
         String action = null;
         String oldAction = null;
         if (mLastBroadcastState == Intent.EXTRA_DOCK_STATE_CAR) {
@@ -359,7 +393,7 @@
                 adjustStatusBarCarModeLocked();
 
                 if (oldAction != null) {
-                    mContext.sendBroadcastAsUser(new Intent(oldAction), UserHandle.ALL);
+                    getContext().sendBroadcastAsUser(new Intent(oldAction), UserHandle.ALL);
                 }
                 mLastBroadcastState = Intent.EXTRA_DOCK_STATE_CAR;
                 action = UiModeManager.ACTION_ENTER_CAR_MODE;
@@ -367,7 +401,7 @@
         } else if (isDeskDockState(mDockState)) {
             if (!isDeskDockState(mLastBroadcastState)) {
                 if (oldAction != null) {
-                    mContext.sendBroadcastAsUser(new Intent(oldAction), UserHandle.ALL);
+                    getContext().sendBroadcastAsUser(new Intent(oldAction), UserHandle.ALL);
                 }
                 mLastBroadcastState = mDockState;
                 action = UiModeManager.ACTION_ENTER_DESK_MODE;
@@ -393,7 +427,7 @@
             Intent intent = new Intent(action);
             intent.putExtra("enableFlags", enableFlags);
             intent.putExtra("disableFlags", disableFlags);
-            mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null,
+            getContext().sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null,
                     mResultReceiver, null, Activity.RESULT_OK, null, null);
 
             // Attempting to make this transition a little more clean, we are going
@@ -491,7 +525,7 @@
             // activity manager take care of both the start and config
             // change.
             Intent homeIntent = buildHomeIntent(category);
-            if (Sandman.shouldStartDockApp(mContext, homeIntent)) {
+            if (Sandman.shouldStartDockApp(getContext(), homeIntent)) {
                 try {
                     int result = ActivityManagerNative.getDefault().startActivityWithConfig(
                             null, null, homeIntent, null, null, null, 0, 0,
@@ -513,14 +547,15 @@
 
         // If we did not start a dock app, then start dreaming if supported.
         if (category != null && !dockAppStarted) {
-            Sandman.startDreamWhenDockedIfAppropriate(mContext);
+            Sandman.startDreamWhenDockedIfAppropriate(getContext());
         }
     }
 
     private void adjustStatusBarCarModeLocked() {
+        final Context context = getContext();
         if (mStatusBarManager == null) {
             mStatusBarManager = (StatusBarManager)
-                    mContext.getSystemService(Context.STATUS_BAR_SERVICE);
+                    context.getSystemService(Context.STATUS_BAR_SERVICE);
         }
 
         // Fear not: StatusBarManagerService manages a list of requests to disable
@@ -536,12 +571,12 @@
 
         if (mNotificationManager == null) {
             mNotificationManager = (NotificationManager)
-                    mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+                    context.getSystemService(Context.NOTIFICATION_SERVICE);
         }
 
         if (mNotificationManager != null) {
             if (mCarModeEnabled) {
-                Intent carModeOffIntent = new Intent(mContext, DisableCarModeActivity.class);
+                Intent carModeOffIntent = new Intent(context, DisableCarModeActivity.class);
 
                 Notification n = new Notification();
                 n.icon = R.drawable.stat_notify_car_mode;
@@ -549,10 +584,10 @@
                 n.flags = Notification.FLAG_ONGOING_EVENT;
                 n.when = 0;
                 n.setLatestEventInfo(
-                        mContext,
-                        mContext.getString(R.string.car_mode_disable_notification_title),
-                        mContext.getString(R.string.car_mode_disable_notification_message),
-                        PendingIntent.getActivityAsUser(mContext, 0, carModeOffIntent, 0,
+                        context,
+                        context.getString(R.string.car_mode_disable_notification_title),
+                        context.getString(R.string.car_mode_disable_notification_message),
+                        PendingIntent.getActivityAsUser(context, 0, carModeOffIntent, 0,
                                 null, UserHandle.CURRENT));
                 mNotificationManager.notifyAsUser(null,
                         R.string.car_mode_disable_notification_title, n, UserHandle.ALL);
@@ -563,7 +598,7 @@
         }
     }
 
-    private void updateTwilight() {
+    void updateTwilight() {
         synchronized (mLock) {
             if (isDoingNightModeLocked() && mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
                 updateComputedNightModeLocked();
@@ -573,36 +608,11 @@
     }
 
     private void updateComputedNightModeLocked() {
-        TwilightState state = mTwilightService.getCurrentState();
+        TwilightState state = mTwilightManager.getCurrentState();
         if (state != null) {
             mComputedNightMode = state.isNight();
         }
     }
 
-    @Override
-    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
-                != PackageManager.PERMISSION_GRANTED) {
 
-            pw.println("Permission Denial: can't dump uimode service from from pid="
-                    + Binder.getCallingPid()
-                    + ", uid=" + Binder.getCallingUid());
-            return;
-        }
-
-        synchronized (mLock) {
-            pw.println("Current UI Mode Service state:");
-            pw.print("  mDockState="); pw.print(mDockState);
-                    pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState);
-            pw.print("  mNightMode="); pw.print(mNightMode);
-                    pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled);
-                    pw.print(" mComputedNightMode="); pw.println(mComputedNightMode);
-            pw.print("  mCurUiMode=0x"); pw.print(Integer.toHexString(mCurUiMode));
-                    pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode));
-            pw.print("  mHoldingConfiguration="); pw.print(mHoldingConfiguration);
-                    pw.print(" mSystemReady="); pw.println(mSystemReady);
-            pw.print("  mTwilightService.getCurrentState()=");
-                    pw.println(mTwilightService.getCurrentState());
-        }
-    }
 }
diff --git a/services/java/com/android/server/UiThread.java b/services/core/java/com/android/server/UiThread.java
similarity index 100%
rename from services/java/com/android/server/UiThread.java
rename to services/core/java/com/android/server/UiThread.java
diff --git a/services/java/com/android/server/UpdateLockService.java b/services/core/java/com/android/server/UpdateLockService.java
similarity index 100%
rename from services/java/com/android/server/UpdateLockService.java
rename to services/core/java/com/android/server/UpdateLockService.java
diff --git a/services/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
similarity index 100%
rename from services/java/com/android/server/VibratorService.java
rename to services/core/java/com/android/server/VibratorService.java
diff --git a/services/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
similarity index 97%
rename from services/java/com/android/server/Watchdog.java
rename to services/core/java/com/android/server/Watchdog.java
index e17f42d..b249953 100644
--- a/services/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -80,9 +80,6 @@
     final ArrayList<HandlerChecker> mHandlerCheckers = new ArrayList<HandlerChecker>();
     final HandlerChecker mMonitorChecker;
     ContentResolver mResolver;
-    BatteryService mBattery;
-    PowerManagerService mPower;
-    AlarmManagerService mAlarm;
     ActivityManagerService mActivity;
 
     int mPhonePid;
@@ -234,13 +231,8 @@
                 "i/o thread", DEFAULT_TIMEOUT));
     }
 
-    public void init(Context context, BatteryService battery,
-            PowerManagerService power, AlarmManagerService alarm,
-            ActivityManagerService activity) {
+    public void init(Context context, ActivityManagerService activity) {
         mResolver = context.getContentResolver();
-        mBattery = battery;
-        mPower = power;
-        mAlarm = alarm;
         mActivity = activity;
 
         context.registerReceiver(new RebootRequestReceiver(),
diff --git a/services/java/com/android/server/WiredAccessoryManager.java b/services/core/java/com/android/server/WiredAccessoryManager.java
similarity index 100%
rename from services/java/com/android/server/WiredAccessoryManager.java
rename to services/core/java/com/android/server/WiredAccessoryManager.java
diff --git a/services/java/com/android/server/accounts/AccountAuthenticatorCache.java b/services/core/java/com/android/server/accounts/AccountAuthenticatorCache.java
similarity index 100%
rename from services/java/com/android/server/accounts/AccountAuthenticatorCache.java
rename to services/core/java/com/android/server/accounts/AccountAuthenticatorCache.java
diff --git a/services/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
similarity index 100%
rename from services/java/com/android/server/accounts/AccountManagerService.java
rename to services/core/java/com/android/server/accounts/AccountManagerService.java
diff --git a/services/java/com/android/server/accounts/IAccountAuthenticatorCache.java b/services/core/java/com/android/server/accounts/IAccountAuthenticatorCache.java
similarity index 100%
rename from services/java/com/android/server/accounts/IAccountAuthenticatorCache.java
rename to services/core/java/com/android/server/accounts/IAccountAuthenticatorCache.java
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
similarity index 100%
rename from services/java/com/android/server/am/ActiveServices.java
rename to services/core/java/com/android/server/am/ActiveServices.java
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
similarity index 98%
rename from services/java/com/android/server/am/ActivityManagerService.java
rename to services/core/java/com/android/server/am/ActivityManagerService.java
index 264a809..3906745 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -28,11 +28,15 @@
 import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
 
 import android.app.AppOpsManager;
+import android.app.IActivityContainer;
+import android.app.IActivityContainerCallback;
 import android.appwidget.AppWidgetManager;
+import android.graphics.Rect;
 import android.util.ArrayMap;
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IAppOpsService;
+import com.android.internal.app.ProcessMap;
 import com.android.internal.app.ProcessStats;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.os.BatteryStatsImpl;
@@ -45,14 +49,12 @@
 import com.android.server.AppOpsService;
 import com.android.server.AttributeCache;
 import com.android.server.IntentResolver;
-import com.android.internal.app.ProcessMap;
 import com.android.server.SystemServer;
 import com.android.server.Watchdog;
 import com.android.server.am.ActivityStack.ActivityState;
 import com.android.server.firewall.IntentFirewall;
 import com.android.server.pm.UserManagerService;
 import com.android.server.wm.AppTransition;
-import com.android.server.wm.StackBox;
 import com.android.server.wm.WindowManagerService;
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
@@ -68,7 +70,6 @@
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManager.RunningTaskInfo;
-import android.app.ActivityManager.StackBoxInfo;
 import android.app.ActivityManager.StackInfo;
 import android.app.ActivityManagerNative;
 import android.app.ActivityOptions;
@@ -331,8 +332,6 @@
 
     public IntentFirewall mIntentFirewall;
 
-    private final boolean mHeadless;
-
     // Whether we should show our dialogs (ANR, crash, etc) or just perform their
     // default actuion automatically.  Important for devices without direct input
     // devices.
@@ -1772,7 +1771,6 @@
     public void setWindowManager(WindowManagerService wm) {
         mWindowManager = wm;
         mStackSupervisor.setWindowManager(wm);
-        wm.createStack(HOME_STACK_ID, -1, StackBox.TASK_STACK_GOES_OVER, 1.0f);
     }
 
     public void startObservingNativeCrashes() {
@@ -1803,7 +1801,7 @@
         m.mFactoryTest = factoryTest;
         m.mIntentFirewall = new IntentFirewall(m.new IntentFirewallInterface());
 
-        m.mStackSupervisor = new ActivityStackSupervisor(m, context, thr.mLooper);
+        m.mStackSupervisor = new ActivityStackSupervisor(m);
 
         m.mBatteryStatsService.publish(context);
         m.mUsageStatsService.publish(context);
@@ -1984,8 +1982,6 @@
 
         mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml"));
 
-        mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
-
         // User 0 is the first and only user that runs at boot.
         mStartedUsers.put(0, new UserStartedState(new UserHandle(0), true));
         mUserLru.add(Integer.valueOf(0));
@@ -2853,13 +2849,6 @@
     }
 
     boolean startHomeActivityLocked(int userId) {
-        if (mHeadless) {
-            // Added because none of the other calls to ensureBootCompleted seem to fire
-            // when running headless.
-            ensureBootCompleted();
-            return false;
-        }
-
         if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
                 && mTopAction == null) {
             // We are running in factory test mode, but unable to find
@@ -5004,7 +4993,7 @@
         // See if the top visible activity is waiting to run in this process...
         if (normalMode) {
             try {
-                if (mStackSupervisor.attachApplicationLocked(app, mHeadless)) {
+                if (mStackSupervisor.attachApplicationLocked(app)) {
                     didSomething = true;
                 }
             } catch (Exception e) {
@@ -7111,23 +7100,28 @@
     }
 
     @Override
-    public int createStack(int taskId, int relativeStackBoxId, int position, float weight) {
+    public IBinder getHomeActivityToken() throws RemoteException {
         enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "createStack()");
-        if (DEBUG_STACK) Slog.d(TAG, "createStack: taskId=" + taskId + " relStackBoxId=" +
-                relativeStackBoxId + " position=" + position + " weight=" + weight);
+                "getHomeActivityToken()");
         synchronized (this) {
-            long ident = Binder.clearCallingIdentity();
-            try {
-                int stackId = mStackSupervisor.createStack();
-                mWindowManager.createStack(stackId, relativeStackBoxId, position, weight);
-                if (taskId > 0) {
-                    moveTaskToStack(taskId, stackId, true);
-                }
-                return stackId;
-            } finally {
-                Binder.restoreCallingIdentity(ident);
+            return mStackSupervisor.getHomeActivityToken();
+        }
+    }
+
+    @Override
+    public IActivityContainer createActivityContainer(IBinder parentActivityToken,
+            IActivityContainerCallback callback) throws RemoteException {
+        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
+                "createActivityContainer()");
+        synchronized (this) {
+            if (parentActivityToken == null) {
+                throw new IllegalArgumentException("parent token must not be null");
             }
+            ActivityRecord r = ActivityRecord.forToken(parentActivityToken);
+            if (r == null) {
+                return null;
+            }
+            return mStackSupervisor.createActivityContainer(r, callback);
         }
     }
 
@@ -7152,99 +7146,40 @@
     }
 
     @Override
-    public void resizeStackBox(int stackBoxId, float weight) {
+    public void resizeStack(int stackBoxId, Rect bounds) {
         enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
                 "resizeStackBox()");
         long ident = Binder.clearCallingIdentity();
         try {
-            mWindowManager.resizeStackBox(stackBoxId, weight);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    private ArrayList<StackInfo> getStacks() {
-        synchronized (this) {
-            ArrayList<ActivityManager.StackInfo> list = new ArrayList<ActivityManager.StackInfo>();
-            ArrayList<ActivityStack> stacks = mStackSupervisor.getStacks();
-            for (ActivityStack stack : stacks) {
-                ActivityManager.StackInfo stackInfo = new ActivityManager.StackInfo();
-                int stackId = stack.mStackId;
-                stackInfo.stackId = stackId;
-                stackInfo.bounds = mWindowManager.getStackBounds(stackId);
-                ArrayList<TaskRecord> tasks = stack.getAllTasks();
-                final int numTasks = tasks.size();
-                int[] taskIds = new int[numTasks];
-                String[] taskNames = new String[numTasks];
-                for (int i = 0; i < numTasks; ++i) {
-                    final TaskRecord task = tasks.get(i);
-                    taskIds[i] = task.taskId;
-                    taskNames[i] = task.origActivity != null ? task.origActivity.flattenToString()
-                            : task.realActivity != null ? task.realActivity.flattenToString()
-                            : task.getTopActivity() != null ? task.getTopActivity().packageName
-                            : "unknown";
-                }
-                stackInfo.taskIds = taskIds;
-                stackInfo.taskNames = taskNames;
-                list.add(stackInfo);
-            }
-            return list;
-        }
-    }
-
-    private void addStackInfoToStackBoxInfo(StackBoxInfo stackBoxInfo, List<StackInfo> stackInfos) {
-        final int stackId = stackBoxInfo.stackId;
-        if (stackId >= 0) {
-            for (StackInfo stackInfo : stackInfos) {
-                if (stackId == stackInfo.stackId) {
-                    stackBoxInfo.stack = stackInfo;
-                    stackInfos.remove(stackInfo);
-                    return;
-                }
-            }
-        } else {
-            addStackInfoToStackBoxInfo(stackBoxInfo.children[0], stackInfos);
-            addStackInfoToStackBoxInfo(stackBoxInfo.children[1], stackInfos);
-        }
-    }
-
-    @Override
-    public List<StackBoxInfo> getStackBoxes() {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "getStackBoxes()");
-        long ident = Binder.clearCallingIdentity();
-        try {
-            List<StackBoxInfo> stackBoxInfos = mWindowManager.getStackBoxInfos();
-            synchronized (this) {
-                List<StackInfo> stackInfos = getStacks();
-                for (StackBoxInfo stackBoxInfo : stackBoxInfos) {
-                    addStackInfoToStackBoxInfo(stackBoxInfo, stackInfos);
-                }
-            }
-            return stackBoxInfos;
+            mWindowManager.resizeStack(stackBoxId, bounds);
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
     }
 
     @Override
-    public StackBoxInfo getStackBoxInfo(int stackBoxId) {
+    public List<StackInfo> getAllStackInfos() {
         enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "getStackBoxInfo()");
+                "getAllStackInfos()");
         long ident = Binder.clearCallingIdentity();
         try {
-            List<StackBoxInfo> stackBoxInfos = mWindowManager.getStackBoxInfos();
-            StackBoxInfo info = null;
             synchronized (this) {
-                List<StackInfo> stackInfos = getStacks();
-                for (StackBoxInfo stackBoxInfo : stackBoxInfos) {
-                    addStackInfoToStackBoxInfo(stackBoxInfo, stackInfos);
-                    if (stackBoxInfo.stackBoxId == stackBoxId) {
-                        info = stackBoxInfo;
-                    }
-                }
+                return mStackSupervisor.getAllStackInfosLocked();
             }
-            return info;
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override
+    public StackInfo getStackInfo(int stackId) {
+        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
+                "getStackInfo()");
+        long ident = Binder.clearCallingIdentity();
+        try {
+            synchronized (this) {
+                return mStackSupervisor.getStackInfoLocked(stackId);
+            }
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
@@ -9500,10 +9435,6 @@
 
     private boolean handleAppCrashLocked(ProcessRecord app, String shortMsg, String longMsg,
             String stackTrace) {
-        if (mHeadless) {
-            Log.e(TAG, "handleAppCrashLocked: " + app.processName);
-            return false;
-        }
         long now = SystemClock.uptimeMillis();
 
         Long crashTime;
@@ -14047,9 +13978,6 @@
      */
     boolean updateConfigurationLocked(Configuration values,
             ActivityRecord starting, boolean persistent, boolean initLocale) {
-        // do nothing if we are headless
-        if (mHeadless) return true;
-
         int changes = 0;
 
         if (values != null) {
@@ -14132,18 +14060,21 @@
 
         boolean kept = true;
         final ActivityStack mainStack = mStackSupervisor.getFocusedStack();
-        if (changes != 0 && starting == null) {
-            // If the configuration changed, and the caller is not already
-            // in the process of starting an activity, then find the top
-            // activity to check if its configuration needs to change.
-            starting = mainStack.topRunningActivityLocked(null);
-        }
+        // mainStack is null during startup.
+        if (mainStack != null) {
+            if (changes != 0 && starting == null) {
+                // If the configuration changed, and the caller is not already
+                // in the process of starting an activity, then find the top
+                // activity to check if its configuration needs to change.
+                starting = mainStack.topRunningActivityLocked(null);
+            }
 
-        if (starting != null) {
-            kept = mainStack.ensureActivityConfigurationLocked(starting, changes);
-            // And we need to make sure at this point that all other activities
-            // are made visible with the correct configuration.
-            mStackSupervisor.ensureActivitiesVisibleLocked(starting, changes);
+            if (starting != null) {
+                kept = mainStack.ensureActivityConfigurationLocked(starting, changes);
+                // And we need to make sure at this point that all other activities
+                // are made visible with the correct configuration.
+                mStackSupervisor.ensureActivitiesVisibleLocked(starting, changes);
+            }
         }
 
         if (values != null && mWindowManager != null) {
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
similarity index 99%
rename from services/java/com/android/server/am/ActivityRecord.java
rename to services/core/java/com/android/server/am/ActivityRecord.java
index 49f29fe..38b01df 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -21,6 +21,7 @@
 import com.android.internal.app.ResolverActivity;
 import com.android.server.AttributeCache;
 import com.android.server.am.ActivityStack.ActivityState;
+import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
 
 import android.app.ActivityOptions;
 import android.app.ResultInfo;
@@ -138,6 +139,7 @@
     boolean forceNewConfig; // force re-create with new config next time
     int launchCount;        // count of launches since last state
     long lastLaunchTime;    // time of last lauch of this activity
+    ArrayList<ActivityStack> mChildContainers = new ArrayList<ActivityStack>();
 
     String stringName;      // for caching of toString().
 
diff --git a/services/java/com/android/server/am/ActivityResult.java b/services/core/java/com/android/server/am/ActivityResult.java
similarity index 100%
rename from services/java/com/android/server/am/ActivityResult.java
rename to services/core/java/com/android/server/am/ActivityResult.java
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
similarity index 98%
rename from services/java/com/android/server/am/ActivityStack.java
rename to services/core/java/com/android/server/am/ActivityStack.java
index 37f4cd7..8faee556 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -39,6 +39,7 @@
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.server.Watchdog;
 import com.android.server.am.ActivityManagerService.ItemMatcher;
+import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
 import com.android.server.wm.AppTransition;
 import com.android.server.wm.TaskGroup;
 import com.android.server.wm.WindowManagerService;
@@ -52,7 +53,6 @@
 import android.app.ResultInfo;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.content.ComponentName;
-import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
@@ -139,8 +139,6 @@
     final ActivityManagerService mService;
     final WindowManagerService mWindowManager;
 
-    final Context mContext;
-
     /**
      * The back history of all previous (and possibly still
      * running) activities.  It contains #TaskRecord objects.
@@ -230,6 +228,8 @@
 
     final int mStackId;
 
+    final ActivityContainer mActivityContainer;
+
     /** Run all ActivityStacks through this */
     final ActivityStackSupervisor mStackSupervisor;
 
@@ -327,14 +327,14 @@
         return count;
     }
 
-    ActivityStack(ActivityManagerService service, Context context, Looper looper, int stackId) {
-        mHandler = new ActivityStackHandler(looper);
-        mService = service;
-        mWindowManager = service.mWindowManager;
-        mStackSupervisor = service.mStackSupervisor;
-        mContext = context;
-        mStackId = stackId;
-        mCurrentUser = service.mCurrentUserId;
+    ActivityStack(ActivityStackSupervisor.ActivityContainer activityContainer) {
+        mActivityContainer = activityContainer;
+        mStackSupervisor = activityContainer.getOuter();
+        mService = mStackSupervisor.mService;
+        mHandler = new ActivityStackHandler(mService.mHandler.getLooper());
+        mWindowManager = mService.mWindowManager;
+        mStackId = activityContainer.mStackId;
+        mCurrentUser = mService.mCurrentUserId;
     }
 
     boolean okToShow(ActivityRecord r) {
@@ -436,25 +436,6 @@
         return null;
     }
 
-    boolean containsApp(ProcessRecord app) {
-        if (app == null) {
-            return false;
-        }
-        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
-            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
-            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord r = activities.get(activityNdx);
-                if (r.finishing) {
-                    continue;
-                }
-                if (r.app == app) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
     final boolean updateLRUListLocked(ActivityRecord r) {
         final boolean hadit = mLRUActivities.remove(r);
         mLRUActivities.add(r);
@@ -465,6 +446,13 @@
         return mStackId == HOME_STACK_ID;
     }
 
+    ArrayList<ActivityStack> getStacksLocked() {
+        if (mActivityContainer.isAttached()) {
+            return mActivityContainer.mActivityDisplayInfo.stacks;
+        }
+        return null;
+    }
+
     /**
      * Returns the top activity in any existing task matching the given
      * Intent.  Returns null if no such task is found.
@@ -1287,17 +1275,7 @@
         if (prevTask != null && prevTask.mOnTopOfHome && prev.finishing && prev.frontOfTask) {
             if (DEBUG_STACK)  mStackSupervisor.validateTopActivitiesLocked();
             if (prevTask == nextTask) {
-                ArrayList<ActivityRecord> activities = prevTask.mActivities;
-                final int numActivities = activities.size();
-                for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
-                    final ActivityRecord r = activities.get(activityNdx);
-                    // r is usually the same as next, but what if two activities were launched
-                    // before prev finished?
-                    if (!r.finishing) {
-                        r.frontOfTask = true;
-                        break;
-                    }
-                }
+                prevTask.setFrontOfTask();
             } else if (prevTask != topTask()) {
                 // This task is going away but it was supposed to return to the home task.
                 // Now the task above it has to return to the home task instead.
@@ -1749,9 +1727,9 @@
         if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task,
                 new RuntimeException("here").fillInStackTrace());
         task.addActivityToTop(r);
+        task.setFrontOfTask();
 
         r.putInHistory();
-        r.frontOfTask = newTask;
         if (!isHomeStack() || numActivities() > 0) {
             // We want to show the starting preview window if we are
             // switching to a new task, or the next activity's process is
@@ -2412,15 +2390,12 @@
         final ArrayList<ActivityRecord> activities = r.task.mActivities;
         final int index = activities.indexOf(r);
         if (index < (activities.size() - 1)) {
-            ActivityRecord next = activities.get(index+1);
-            if (r.frontOfTask) {
-                // The next activity is now the front of the task.
-                next.frontOfTask = true;
-            }
+            r.task.setFrontOfTask();
             if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
                 // If the caller asked that this activity (and all above it)
                 // be cleared when the task is reset, don't lose that information,
                 // but propagate it up to the next activity.
+                ActivityRecord next = activities.get(index+1);
                 next.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
             }
         }
diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
similarity index 76%
rename from services/java/com/android/server/am/ActivityStackSupervisor.java
rename to services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 483b4a0..f1ac7fe 100644
--- a/services/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -34,8 +34,11 @@
 
 import android.app.Activity;
 import android.app.ActivityManager;
+import android.app.ActivityManager.StackInfo;
 import android.app.ActivityOptions;
 import android.app.AppGlobals;
+import android.app.IActivityContainer;
+import android.app.IActivityContainerCallback;
 import android.app.IActivityManager;
 import android.app.IApplicationThread;
 import android.app.IThumbnailReceiver;
@@ -53,6 +56,9 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.res.Configuration;
+import android.graphics.Point;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManager.DisplayListener;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Debug;
@@ -68,13 +74,15 @@
 import android.os.UserHandle;
 import android.util.EventLog;
 import android.util.Slog;
-import android.util.SparseIntArray;
+import android.util.SparseArray;
 
+import android.util.SparseIntArray;
+import android.view.Display;
+import android.view.DisplayInfo;
 import com.android.internal.app.HeavyWeightSwitcherActivity;
 import com.android.internal.os.TransferPipe;
 import com.android.server.am.ActivityManagerService.PendingActivityLaunch;
 import com.android.server.am.ActivityStack.ActivityState;
-import com.android.server.wm.StackBox;
 import com.android.server.wm.WindowManagerService;
 
 import java.io.FileDescriptor;
@@ -83,7 +91,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
-public final class ActivityStackSupervisor {
+public final class ActivityStackSupervisor implements DisplayListener {
     static final boolean DEBUG = ActivityManagerService.DEBUG || false;
     static final boolean DEBUG_ADD_REMOVE = DEBUG || false;
     static final boolean DEBUG_APP = DEBUG || false;
@@ -107,19 +115,22 @@
     static final int RESUME_TOP_ACTIVITY_MSG = FIRST_SUPERVISOR_STACK_MSG + 2;
     static final int SLEEP_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 3;
     static final int LAUNCH_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 4;
+    static final int HANDLE_DISPLAY_ADDED = FIRST_SUPERVISOR_STACK_MSG + 5;
+    static final int HANDLE_DISPLAY_CHANGED = FIRST_SUPERVISOR_STACK_MSG + 6;
+    static final int HANDLE_DISPLAY_REMOVED = FIRST_SUPERVISOR_STACK_MSG + 7;
+
 
     // For debugging to make sure the caller when acquiring/releasing our
     // wake lock is the system process.
     static final boolean VALIDATE_WAKE_LOCK_CALLER = false;
 
     final ActivityManagerService mService;
-    final Context mContext;
-    final Looper mLooper;
 
     final ActivityStackSupervisorHandler mHandler;
 
     /** Short cut */
     WindowManagerService mWindowManager;
+    DisplayManager mDisplayManager;
 
     /** Dismiss the keyguard after the next activity is displayed? */
     boolean mDismissKeyguardOnNextActivity = false;
@@ -142,14 +153,10 @@
      * DO NOT ACCESS DIRECTLY - It may be null, use getFocusedStack() */
     private ActivityStack mFocusedStack;
 
-    /** All the non-launcher stacks */
-    private ArrayList<ActivityStack> mStacks = new ArrayList<ActivityStack>();
-
-    private static final int STACK_STATE_HOME_IN_FRONT = 0;
-    private static final int STACK_STATE_HOME_TO_BACK = 1;
-    private static final int STACK_STATE_HOME_IN_BACK = 2;
-    private static final int STACK_STATE_HOME_TO_FRONT = 3;
-    private int mStackState = STACK_STATE_HOME_IN_FRONT;
+    /** If this is the same as mFocusedStack then the activity on the top of the focused stack has
+     * been resumed. If stacks are changing position this will hold the old stack until the new
+     * stack becomes resumed after which it will be set to the new stack. */
+    private ActivityStack mLastFocusedStack;
 
     /** List of activities that are waiting for a new activity to become visible before completing
      * whatever operation they are supposed to do. */
@@ -206,14 +213,17 @@
     /** Stack id of the front stack when user switched, indexed by userId. */
     SparseIntArray mUserStackInFront = new SparseIntArray(2);
 
-    public ActivityStackSupervisor(ActivityManagerService service, Context context,
-            Looper looper) {
+    /** Mapping from (ActivityStack/TaskStack).mStackId to their current state */
+    SparseArray<ActivityContainer> mActivityContainers = new SparseArray<ActivityContainer>();
+
+    /** Mapping from displayId to display current state */
+    SparseArray<ActivityDisplayInfo> mDisplayInfos = new SparseArray<ActivityDisplayInfo>();
+
+    public ActivityStackSupervisor(ActivityManagerService service) {
         mService = service;
-        mContext = context;
-        mLooper = looper;
-        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+        PowerManager pm = (PowerManager)mService.mContext.getSystemService(Context.POWER_SERVICE);
         mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
-        mHandler = new ActivityStackSupervisorHandler(looper);
+        mHandler = new ActivityStackSupervisorHandler(mService.mHandler.getLooper());
         if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != Process.myUid()) {
             throw new IllegalStateException("Calling must be system uid");
         }
@@ -223,9 +233,23 @@
     }
 
     void setWindowManager(WindowManagerService wm) {
-        mWindowManager = wm;
-        mHomeStack = new ActivityStack(mService, mContext, mLooper, HOME_STACK_ID);
-        mStacks.add(mHomeStack);
+        synchronized (mService) {
+            mWindowManager = wm;
+
+            mDisplayManager =
+                    (DisplayManager)mService.mContext.getSystemService(Context.DISPLAY_SERVICE);
+            mDisplayManager.registerDisplayListener(this, null);
+
+            Display[] displays = mDisplayManager.getDisplays();
+            for (int displayNdx = displays.length - 1; displayNdx >= 0; --displayNdx) {
+                final int displayId = displays[displayNdx].getDisplayId();
+                ActivityDisplayInfo info = new ActivityDisplayInfo(displayId);
+                mDisplayInfos.put(displayId, info);
+            }
+
+            createStackOnDisplay(null, HOME_STACK_ID, Display.DEFAULT_DISPLAY);
+            mHomeStack = mFocusedStack = mLastFocusedStack = getStack(HOME_STACK_ID);
+        }
     }
 
     void dismissKeyguard() {
@@ -237,43 +261,38 @@
     }
 
     ActivityStack getFocusedStack() {
-        if (mFocusedStack == null) {
-            return mHomeStack;
-        }
-        switch (mStackState) {
-            case STACK_STATE_HOME_IN_FRONT:
-            case STACK_STATE_HOME_TO_FRONT:
-                return mHomeStack;
-            case STACK_STATE_HOME_IN_BACK:
-            case STACK_STATE_HOME_TO_BACK:
-            default:
-                return mFocusedStack;
-        }
+        return mFocusedStack;
     }
 
     ActivityStack getLastStack() {
-        switch (mStackState) {
-            case STACK_STATE_HOME_IN_FRONT:
-            case STACK_STATE_HOME_TO_BACK:
-                return mHomeStack;
-            case STACK_STATE_HOME_TO_FRONT:
-            case STACK_STATE_HOME_IN_BACK:
-            default:
-                return mFocusedStack;
-        }
+        return mLastFocusedStack;
     }
 
+    // TODO: Split into two methods isFrontStack for any visible stack and isFrontmostStack for the
+    // top of all visible stacks.
     boolean isFrontStack(ActivityStack stack) {
-        return !(stack.isHomeStack() ^ getFocusedStack().isHomeStack());
+        ArrayList<ActivityStack> stacks = stack.getStacksLocked();
+        if (stacks != null && !stacks.isEmpty()) {
+            return stack == stacks.get(stacks.size() - 1);
+        }
+        return false;
     }
 
     void moveHomeStack(boolean toFront) {
-        final boolean homeInFront = isFrontStack(mHomeStack);
-        if (homeInFront ^ toFront) {
-            if (DEBUG_STACK) Slog.d(TAG, "moveHomeTask: mStackState old=" +
-                    stackStateToString(mStackState) + " new=" + stackStateToString(homeInFront ?
-                    STACK_STATE_HOME_TO_BACK : STACK_STATE_HOME_TO_FRONT));
-            mStackState = homeInFront ? STACK_STATE_HOME_TO_BACK : STACK_STATE_HOME_TO_FRONT;
+        ArrayList<ActivityStack> stacks = mHomeStack.getStacksLocked();
+        int topNdx = stacks.size() - 1;
+        if (topNdx <= 0) {
+            return;
+        }
+        ActivityStack topStack = stacks.get(topNdx);
+        final boolean homeInFront = topStack == mHomeStack;
+        if (homeInFront != toFront) {
+            mLastFocusedStack = topStack;
+            stacks.remove(mHomeStack);
+            stacks.add(toFront ? topNdx : 0, mHomeStack);
+            mFocusedStack = stacks.get(topNdx);
+            if (DEBUG_STACK) Slog.d(TAG, "moveHomeTask: topStack old=" + topStack + " new="
+                    + mFocusedStack);
         }
     }
 
@@ -301,21 +320,29 @@
     }
 
     TaskRecord anyTaskForIdLocked(int id) {
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            ActivityStack stack = mStacks.get(stackNdx);
-            TaskRecord task = stack.taskForIdLocked(id);
-            if (task != null) {
-                return task;
+        int numDisplays = mDisplayInfos.size();
+        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+            ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                ActivityStack stack = stacks.get(stackNdx);
+                TaskRecord task = stack.taskForIdLocked(id);
+                if (task != null) {
+                    return task;
+                }
             }
         }
         return null;
     }
 
     ActivityRecord isInAnyStackLocked(IBinder token) {
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityRecord r = mStacks.get(stackNdx).isInStackLocked(token);
-            if (r != null) {
-                return r;
+        int numDisplays = mDisplayInfos.size();
+        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+            ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityRecord r = stacks.get(stackNdx).isInStackLocked(token);
+                if (r != null) {
+                    return r;
+                }
             }
         }
         return null;
@@ -340,14 +367,11 @@
         }
         if (stack.removeTask(task) && !stack.isHomeStack()) {
             if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing stack " + stack);
-            mStacks.remove(stack);
+            stack.mActivityContainer.detachLocked();
             final int stackId = stack.mStackId;
             final int nextStackId = mWindowManager.removeStack(stackId);
             // TODO: Perhaps we need to let the ActivityManager determine the next focus...
-            if (mFocusedStack == null || mFocusedStack.mStackId == stackId) {
-                // If this is the last app stack, set mFocusedStack to null.
-                mFocusedStack = nextStackId == HOME_STACK_ID ? null : getStack(nextStackId);
-            }
+            mFocusedStack = getStack(nextStackId);
         }
     }
 
@@ -366,29 +390,29 @@
         return resumedActivity;
     }
 
-    boolean attachApplicationLocked(ProcessRecord app, boolean headless) throws Exception {
-        boolean didSomething = false;
+    boolean attachApplicationLocked(ProcessRecord app) throws Exception {
         final String processName = app.processName;
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            if (!isFrontStack(stack)) {
-                continue;
-            }
-            ActivityRecord hr = stack.topRunningActivityLocked(null);
-            if (hr != null) {
-                if (hr.app == null && app.uid == hr.info.applicationInfo.uid
-                        && processName.equals(hr.processName)) {
-                    try {
-                        if (headless) {
-                            Slog.e(TAG, "Starting activities not supported on headless device: "
-                                    + hr);
-                        } else if (realStartActivityLocked(hr, app, true, true)) {
-                            didSomething = true;
+        boolean didSomething = false;
+        for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) {
+            ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                if (!isFrontStack(stack)) {
+                    continue;
+                }
+                ActivityRecord hr = stack.topRunningActivityLocked(null);
+                if (hr != null) {
+                    if (hr.app == null && app.uid == hr.info.applicationInfo.uid
+                            && processName.equals(hr.processName)) {
+                        try {
+                            if (realStartActivityLocked(hr, app, true, true)) {
+                                didSomething = true;
+                            }
+                        } catch (Exception e) {
+                            Slog.w(TAG, "Exception in new application when starting activity "
+                                  + hr.intent.getComponent().flattenToShortString(), e);
+                            throw e;
                         }
-                    } catch (Exception e) {
-                        Slog.w(TAG, "Exception in new application when starting activity "
-                              + hr.intent.getComponent().flattenToShortString(), e);
-                        throw e;
                     }
                 }
             }
@@ -400,53 +424,52 @@
     }
 
     boolean allResumedActivitiesIdle() {
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            if (!isFrontStack(stack)) {
-                continue;
-            }
-            final ActivityRecord resumedActivity = stack.mResumedActivity;
-            if (resumedActivity == null || !resumedActivity.idle) {
-                return false;
+        for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) {
+            ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                if (!isFrontStack(stack)) {
+                    continue;
+                }
+                final ActivityRecord resumedActivity = stack.mResumedActivity;
+                if (resumedActivity == null || !resumedActivity.idle) {
+                    return false;
+                }
             }
         }
         return true;
     }
 
     boolean allResumedActivitiesComplete() {
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            if (isFrontStack(stack)) {
-                final ActivityRecord r = stack.mResumedActivity;
-                if (r != null && r.state != ActivityState.RESUMED) {
-                    return false;
+        for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) {
+            ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                if (isFrontStack(stack)) {
+                    final ActivityRecord r = stack.mResumedActivity;
+                    if (r != null && r.state != ActivityState.RESUMED) {
+                        return false;
+                    }
                 }
             }
         }
         // TODO: Not sure if this should check if all Paused are complete too.
-        switch (mStackState) {
-            case STACK_STATE_HOME_TO_BACK:
-                if (DEBUG_STACK) Slog.d(TAG, "allResumedActivitiesComplete: mStackState old=" +
-                        stackStateToString(STACK_STATE_HOME_TO_BACK) + " new=" +
-                        stackStateToString(STACK_STATE_HOME_IN_BACK));
-                mStackState = STACK_STATE_HOME_IN_BACK;
-                break;
-            case STACK_STATE_HOME_TO_FRONT:
-                if (DEBUG_STACK) Slog.d(TAG, "allResumedActivitiesComplete: mStackState old=" +
-                        stackStateToString(STACK_STATE_HOME_TO_FRONT) + " new=" +
-                        stackStateToString(STACK_STATE_HOME_IN_FRONT));
-                mStackState = STACK_STATE_HOME_IN_FRONT;
-                break;
-        }
+        if (DEBUG_STACK) Slog.d(TAG,
+                "allResumedActivitiesComplete: mLastFocusedStack changing from=" +
+                mLastFocusedStack + " to=" + mFocusedStack);
+        mLastFocusedStack = mFocusedStack;
         return true;
     }
 
     boolean allResumedActivitiesVisible() {
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            final ActivityRecord r = stack.mResumedActivity;
-            if (r != null && (!r.nowVisible || r.waitingVisible)) {
-                return false;
+        for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) {
+            ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                final ActivityRecord r = stack.mResumedActivity;
+                if (r != null && (!r.nowVisible || r.waitingVisible)) {
+                    return false;
+                }
             }
         }
         return true;
@@ -459,13 +482,16 @@
      */
     boolean pauseBackStacks(boolean userLeaving) {
         boolean someActivityPaused = false;
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            if (!isFrontStack(stack) && stack.mResumedActivity != null) {
-                if (DEBUG_STATES) Slog.d(TAG, "pauseBackStacks: stack=" + stack +
-                        " mResumedActivity=" + stack.mResumedActivity);
-                stack.startPausingLocked(userLeaving, false);
-                someActivityPaused = true;
+        for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) {
+            ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                if (!isFrontStack(stack) && stack.mResumedActivity != null) {
+                    if (DEBUG_STATES) Slog.d(TAG, "pauseBackStacks: stack=" + stack +
+                            " mResumedActivity=" + stack.mResumedActivity);
+                    stack.startPausingLocked(userLeaving, false);
+                    someActivityPaused = true;
+                }
             }
         }
         return someActivityPaused;
@@ -473,17 +499,20 @@
 
     boolean allPausedActivitiesComplete() {
         boolean pausing = true;
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            final ActivityRecord r = stack.mPausingActivity;
-            if (r != null && r.state != ActivityState.PAUSED
-                    && r.state != ActivityState.STOPPED
-                    && r.state != ActivityState.STOPPING) {
-                if (DEBUG_STATES) {
-                    Slog.d(TAG, "allPausedActivitiesComplete: r=" + r + " state=" + r.state);
-                    pausing = false;
-                } else {
-                    return false;
+        for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) {
+            ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                final ActivityRecord r = stack.mPausingActivity;
+                if (r != null && r.state != ActivityState.PAUSED
+                        && r.state != ActivityState.STOPPED
+                        && r.state != ActivityState.STOPPING) {
+                    if (DEBUG_STATES) {
+                        Slog.d(TAG, "allPausedActivitiesComplete: r=" + r + " state=" + r.state);
+                        pausing = false;
+                    } else {
+                        return false;
+                    }
                 }
             }
         }
@@ -525,8 +554,10 @@
             return r;
         }
 
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
+        // Return to the home stack.
+        final ArrayList<ActivityStack> stacks = mHomeStack.getStacksLocked();
+        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = stacks.get(stackNdx);
             if (stack != focusedStack && isFrontStack(stack)) {
                 r = stack.topRunningActivityLocked(null);
                 if (r != null) {
@@ -542,15 +573,19 @@
         ActivityRecord r = null;
 
         // Gather all of the running tasks for each stack into runningTaskLists.
-        final int numStacks = mStacks.size();
-        ArrayList<RunningTaskInfo>[] runningTaskLists = new ArrayList[numStacks];
-        for (int stackNdx = numStacks - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            ArrayList<RunningTaskInfo> stackTaskList = new ArrayList<RunningTaskInfo>();
-            runningTaskLists[stackNdx] = stackTaskList;
-            final ActivityRecord ar = stack.getTasksLocked(receiver, pending, stackTaskList);
-            if (isFrontStack(stack)) {
-                r = ar;
+        ArrayList<ArrayList<RunningTaskInfo>> runningTaskLists =
+                new ArrayList<ArrayList<RunningTaskInfo>>();
+        final int numDisplays = mDisplayInfos.size();
+        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+            ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                ArrayList<RunningTaskInfo> stackTaskList = new ArrayList<RunningTaskInfo>();
+                runningTaskLists.add(stackTaskList);
+                final ActivityRecord ar = stack.getTasksLocked(receiver, pending, stackTaskList);
+                if (r == null && isFrontStack(stack)) {
+                    r = ar;
+                }
             }
         }
 
@@ -559,8 +594,9 @@
         while (maxNum > 0) {
             long mostRecentActiveTime = Long.MIN_VALUE;
             ArrayList<RunningTaskInfo> selectedStackList = null;
-            for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-                ArrayList<RunningTaskInfo> stackTaskList = runningTaskLists[stackNdx];
+            final int numTaskLists = runningTaskLists.size();
+            for (int stackNdx = 0; stackNdx < numTaskLists; ++stackNdx) {
+                ArrayList<RunningTaskInfo> stackTaskList = runningTaskLists.get(stackNdx);
                 if (!stackTaskList.isEmpty()) {
                     final long lastActiveTime = stackTaskList.get(0).lastActiveTime;
                     if (lastActiveTime > mostRecentActiveTime) {
@@ -1266,7 +1302,7 @@
                 if (mFocusedStack != taskStack) {
                     if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
                             "adjustStackFocus: Setting focused stack to r=" + r + " task=" + task);
-                    mFocusedStack = taskStack.isHomeStack() ? null : taskStack;
+                    mFocusedStack = taskStack;
                 } else {
                     if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
                         "adjustStackFocus: Focused stack already=" + mFocusedStack);
@@ -1274,25 +1310,28 @@
                 return taskStack;
             }
 
-            if (mFocusedStack != null) {
+            if (mFocusedStack != mHomeStack) {
                 if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
                         "adjustStackFocus: Have a focused stack=" + mFocusedStack);
                 return mFocusedStack;
             }
 
-            for (int stackNdx = mStacks.size() - 1; stackNdx > 0; --stackNdx) {
-                ActivityStack stack = mStacks.get(stackNdx);
-                if (!stack.isHomeStack()) {
-                    if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
-                            "adjustStackFocus: Setting focused stack=" + stack);
-                    mFocusedStack = stack;
-                    return mFocusedStack;
+            int numDisplays = mDisplayInfos.size();
+            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+                ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks;
+                for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                    ActivityStack stack = stacks.get(stackNdx);
+                    if (!stack.isHomeStack()) {
+                        if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
+                                "adjustStackFocus: Setting focused stack=" + stack);
+                        mFocusedStack = stack;
+                        return mFocusedStack;
+                    }
                 }
             }
 
-            // Time to create the first app stack for this user.
-            int stackId =
-                    mService.createStack(-1, HOME_STACK_ID, StackBox.TASK_STACK_GOES_OVER, 1.0f);
+            // Need to create an app stack for this user.
+            int stackId = createStackOnDisplay(null, getNextStackId(), Display.DEFAULT_DISPLAY);
             if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: New stack r=" + r +
                     " stackId=" + stackId);
             mFocusedStack = getStack(stackId);
@@ -1302,30 +1341,10 @@
     }
 
     void setFocusedStack(ActivityRecord r) {
-        if (r == null) {
-            return;
-        }
-        if (!r.isApplicationActivity() || (r.task != null && !r.task.isApplicationTask())) {
-            if (mStackState != STACK_STATE_HOME_IN_FRONT) {
-                if (DEBUG_STACK || DEBUG_FOCUS) Slog.d(TAG, "setFocusedStack: mStackState old=" +
-                        stackStateToString(mStackState) + " new=" +
-                        stackStateToString(STACK_STATE_HOME_TO_FRONT) +
-                        " Callers=" + Debug.getCallers(3));
-                mStackState = STACK_STATE_HOME_TO_FRONT;
-            }
-        } else {
-            if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
-                    "setFocusedStack: Setting focused stack to r=" + r + " task=" + r.task +
-                    " Callers=" + Debug.getCallers(3));
-            final ActivityStack taskStack = r.task.stack;
-            mFocusedStack = taskStack.isHomeStack() ? null : taskStack;
-            if (mStackState != STACK_STATE_HOME_IN_BACK) {
-                if (DEBUG_STACK) Slog.d(TAG, "setFocusedStack: mStackState old=" +
-                        stackStateToString(mStackState) + " new=" +
-                        stackStateToString(STACK_STATE_HOME_TO_BACK) +
-                        " Callers=" + Debug.getCallers(3));
-                mStackState = STACK_STATE_HOME_TO_BACK;
-            }
+        if (r != null) {
+            final boolean isHomeActivity =
+                    !r.isApplicationActivity() || (r.task != null && !r.task.isApplicationTask());
+            moveHomeStack(isHomeActivity);
         }
     }
 
@@ -1941,17 +1960,21 @@
 
     boolean handleAppDiedLocked(ProcessRecord app) {
         boolean hasVisibleActivities = false;
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            hasVisibleActivities |= mStacks.get(stackNdx).handleAppDiedLocked(app);
+        for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                hasVisibleActivities |= stacks.get(stackNdx).handleAppDiedLocked(app);
+            }
         }
         return hasVisibleActivities;
     }
 
     void closeSystemDialogsLocked() {
-        final int numStacks = mStacks.size();
-        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            stack.closeSystemDialogsLocked();
+        for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                stacks.get(stackNdx).closeSystemDialogsLocked();
+            }
         }
     }
 
@@ -1964,11 +1987,14 @@
      */
     boolean forceStopPackageLocked(String name, boolean doit, boolean evenPersistent, int userId) {
         boolean didSomething = false;
-        final int numStacks = mStacks.size();
-        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            if (stack.forceStopPackageLocked(name, doit, evenPersistent, userId)) {
-                didSomething = true;
+        for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks;
+            final int numStacks = stacks.size();
+            for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                if (stack.forceStopPackageLocked(name, doit, evenPersistent, userId)) {
+                    didSomething = true;
+                }
             }
         }
         return didSomething;
@@ -1983,15 +2009,18 @@
         // we don't blow away the previous app if this activity is being
         // hosted by the process that is actually still the foreground.
         ProcessRecord fgApp = null;
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            if (isFrontStack(stack)) {
-                if (stack.mResumedActivity != null) {
-                    fgApp = stack.mResumedActivity.app;
-                } else if (stack.mPausingActivity != null) {
-                    fgApp = stack.mPausingActivity.app;
+        for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                if (isFrontStack(stack)) {
+                    if (stack.mResumedActivity != null) {
+                        fgApp = stack.mResumedActivity.app;
+                    } else if (stack.mPausingActivity != null) {
+                        fgApp = stack.mPausingActivity.app;
+                    }
+                    break;
                 }
-                break;
             }
         }
 
@@ -2015,13 +2044,16 @@
             targetStack = getFocusedStack();
         }
         boolean result = false;
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            if (isFrontStack(stack)) {
-                if (stack == targetStack) {
-                    result = stack.resumeTopActivityLocked(target, targetOptions);
-                } else {
-                    stack.resumeTopActivityLocked(null);
+        for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                if (isFrontStack(stack)) {
+                    if (stack == targetStack) {
+                        result = stack.resumeTopActivityLocked(target, targetOptions);
+                    } else {
+                        stack.resumeTopActivityLocked(null);
+                    }
                 }
             }
         }
@@ -2029,38 +2061,91 @@
     }
 
     void finishTopRunningActivityLocked(ProcessRecord app) {
-        final int numStacks = mStacks.size();
-        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            stack.finishTopRunningActivityLocked(app);
+        for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks;
+            final int numStacks = stacks.size();
+            for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                stack.finishTopRunningActivityLocked(app);
+            }
         }
     }
 
     void findTaskToMoveToFrontLocked(int taskId, int flags, Bundle options) {
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            if (mStacks.get(stackNdx).findTaskToMoveToFrontLocked(taskId, flags, options)) {
-                if (DEBUG_STACK) Slog.d(TAG, "findTaskToMoveToFront: moved to front of stack=" +
-                        mStacks.get(stackNdx));
-                return;
+        for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                if (stacks.get(stackNdx).findTaskToMoveToFrontLocked(taskId, flags, options)) {
+                    if (DEBUG_STACK) Slog.d(TAG, "findTaskToMoveToFront: moved to front of stack="
+                            + stacks.get(stackNdx));
+                    return;
+                }
             }
         }
     }
 
     ActivityStack getStack(int stackId) {
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            if (stack.getStackId() == stackId) {
-                return stack;
-            }
+        ActivityContainer activityContainer = mActivityContainers.get(stackId);
+        if (activityContainer != null) {
+            return activityContainer.mStack;
         }
         return null;
     }
 
     ArrayList<ActivityStack> getStacks() {
-        return new ArrayList<ActivityStack>(mStacks);
+        ArrayList<ActivityStack> allStacks = new ArrayList<ActivityStack>();
+        for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) {
+            allStacks.addAll(mDisplayInfos.valueAt(displayNdx).stacks);
+        }
+        return allStacks;
     }
 
-    int createStack() {
+    IBinder getHomeActivityToken() {
+        final ArrayList<TaskRecord> tasks = mHomeStack.getAllTasks();
+        for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+            final TaskRecord task = tasks.get(taskNdx);
+            if (task.isHomeTask()) {
+                final ArrayList<ActivityRecord> activities = task.mActivities;
+                for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                    final ActivityRecord r = activities.get(activityNdx);
+                    if (r.isHomeActivity()) {
+                        return r.appToken;
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    ActivityContainer createActivityContainer(ActivityRecord parentActivity, int stackId,
+            IActivityContainerCallback callback) {
+        ActivityContainer activityContainer = new ActivityContainer(parentActivity, stackId,
+                callback);
+        mActivityContainers.put(stackId, activityContainer);
+        if (parentActivity != null) {
+            parentActivity.mChildContainers.add(activityContainer.mStack);
+        }
+        return activityContainer;
+    }
+
+    ActivityContainer createActivityContainer(ActivityRecord parentActivity,
+            IActivityContainerCallback callback) {
+        return createActivityContainer(parentActivity, getNextStackId(), callback);
+    }
+
+    private int createStackOnDisplay(ActivityRecord parentActivity, int stackId, int displayId) {
+        ActivityDisplayInfo displayInfo = mDisplayInfos.get(displayId);
+        if (displayInfo == null) {
+            return -1;
+        }
+
+        ActivityContainer activityContainer =
+                createActivityContainer(parentActivity, stackId, null);
+        activityContainer.attachToDisplayLocked(displayInfo);
+        return stackId;
+    }
+
+    int getNextStackId() {
         while (true) {
             if (++mLastStackId <= HOME_STACK_ID) {
                 mLastStackId = HOME_STACK_ID + 1;
@@ -2069,7 +2154,6 @@
                 break;
             }
         }
-        mStacks.add(new ActivityStack(mService, mContext, mLooper, mLastStackId));
         return mLastStackId;
     }
 
@@ -2091,15 +2175,18 @@
 
     ActivityRecord findTaskLocked(ActivityRecord r) {
         if (DEBUG_TASKS) Slog.d(TAG, "Looking for task of " + r);
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            if (!r.isApplicationActivity() && !stack.isHomeStack()) {
-                if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: " + stack);
-                continue;
-            }
-            final ActivityRecord ar = stack.findTaskLocked(r);
-            if (ar != null) {
-                return ar;
+        for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                if (!r.isApplicationActivity() && !stack.isHomeStack()) {
+                    if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: " + stack);
+                    continue;
+                }
+                final ActivityRecord ar = stack.findTaskLocked(r);
+                if (ar != null) {
+                    return ar;
+                }
             }
         }
         if (DEBUG_TASKS) Slog.d(TAG, "No task found");
@@ -2107,10 +2194,13 @@
     }
 
     ActivityRecord findActivityLocked(Intent intent, ActivityInfo info) {
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityRecord ar = mStacks.get(stackNdx).findActivityLocked(intent, info);
-            if (ar != null) {
-                return ar;
+        for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityRecord ar = stacks.get(stackNdx).findActivityLocked(intent, info);
+                if (ar != null) {
+                    return ar;
+                }
             }
         }
         return null;
@@ -2138,8 +2228,11 @@
         final long endTime = System.currentTimeMillis() + timeout;
         while (true) {
             boolean cantShutdown = false;
-            for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                cantShutdown |= mStacks.get(stackNdx).checkReadyForSleepLocked();
+            for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) {
+                final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks;
+                for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                    cantShutdown |= stacks.get(stackNdx).checkReadyForSleepLocked();
+                }
             }
             if (cantShutdown) {
                 long timeRemaining = endTime - System.currentTimeMillis();
@@ -2170,11 +2263,14 @@
         if (mGoingToSleep.isHeld()) {
             mGoingToSleep.release();
         }
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            stack.awakeFromSleepingLocked();
-            if (isFrontStack(stack)) {
-                resumeTopActivitiesLocked();
+        for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                stack.awakeFromSleepingLocked();
+                if (isFrontStack(stack)) {
+                    resumeTopActivitiesLocked();
+                }
             }
         }
         mGoingToSleepActivities.clear();
@@ -2193,8 +2289,11 @@
 
         if (!mSleepTimeout) {
             boolean dontSleep = false;
-            for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                dontSleep |= mStacks.get(stackNdx).checkReadyForSleepLocked();
+            for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) {
+                final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks;
+                for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                    dontSleep |= stacks.get(stackNdx).checkReadyForSleepLocked();
+                }
             }
 
             if (mStoppingActivities.size() > 0) {
@@ -2217,8 +2316,11 @@
             }
         }
 
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            mStacks.get(stackNdx).goToSleep();
+        for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                stacks.get(stackNdx).goToSleep();
+            }
         }
 
         removeSleepTimeouts();
@@ -2245,37 +2347,45 @@
     }
 
     void handleAppCrashLocked(ProcessRecord app) {
-        final int numStacks = mStacks.size();
-        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            stack.handleAppCrashLocked(app);
+        for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks;
+            final int numStacks = stacks.size();
+            for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                stack.handleAppCrashLocked(app);
+            }
         }
     }
 
     void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges) {
         // First the front stacks. In case any are not fullscreen and are in front of home.
         boolean showHomeBehindStack = false;
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            if (isFrontStack(stack)) {
-                showHomeBehindStack =
-                        stack.ensureActivitiesVisibleLocked(starting, configChanges);
-            }
-        }
-        // Now do back stacks.
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            if (!isFrontStack(stack)) {
-                stack.ensureActivitiesVisibleLocked(starting, configChanges, showHomeBehindStack);
+        for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks;
+            final int topStackNdx = stacks.size() - 1;
+            for (int stackNdx = topStackNdx; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                if (stackNdx == topStackNdx) {
+                    // Top stack.
+                    showHomeBehindStack =
+                            stack.ensureActivitiesVisibleLocked(starting, configChanges);
+                } else {
+                    // Back stack.
+                    stack.ensureActivitiesVisibleLocked(starting, configChanges,
+                            showHomeBehindStack);
+                }
             }
         }
     }
 
     void scheduleDestroyAllActivities(ProcessRecord app, String reason) {
-        final int numStacks = mStacks.size();
-        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            stack.scheduleDestroyActivities(app, false, reason);
+        for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks;
+            final int numStacks = stacks.size();
+            for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                stack.scheduleDestroyActivities(app, false, reason);
+            }
         }
     }
 
@@ -2285,8 +2395,11 @@
         mCurrentUser = userId;
 
         mStartingUsers.add(uss);
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            mStacks.get(stackNdx).switchUserLocked(userId);
+        for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                stacks.get(stackNdx).switchUserLocked(userId);
+            }
         }
 
         ActivityStack stack = getStack(restoreStackId);
@@ -2340,8 +2453,9 @@
     }
 
     void validateTopActivitiesLocked() {
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
+        // FIXME
+/*        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = stacks.get(stackNdx);
             final ActivityRecord r = stack.topRunningActivityLocked(null);
             final ActivityState state = r == null ? ActivityState.DESTROYED : r.state;
             if (isFrontStack(stack)) {
@@ -2371,23 +2485,14 @@
                 }
             }
         }
-    }
-
-    private static String stackStateToString(int stackState) {
-        switch (stackState) {
-            case STACK_STATE_HOME_IN_FRONT: return "STACK_STATE_HOME_IN_FRONT";
-            case STACK_STATE_HOME_TO_BACK: return "STACK_STATE_HOME_TO_BACK";
-            case STACK_STATE_HOME_IN_BACK: return "STACK_STATE_HOME_IN_BACK";
-            case STACK_STATE_HOME_TO_FRONT: return "STACK_STATE_HOME_TO_FRONT";
-            default: return "Unknown stackState=" + stackState;
-        }
+*/
     }
 
     public void dump(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.print("mDismissKeyguardOnNextActivity=");
                 pw.println(mDismissKeyguardOnNextActivity);
         pw.print(prefix); pw.print("mFocusedStack=" + mFocusedStack);
-                pw.print(" mStackState="); pw.println(stackStateToString(mStackState));
+                pw.print(" mLastFocusedStack="); pw.println(mLastFocusedStack);
         pw.print(prefix); pw.println("mSleepTimeout=" + mSleepTimeout);
         pw.print(prefix); pw.println("mCurTaskId=" + mCurTaskId);
         pw.print(prefix); pw.println("mUserStackInFront=" + mUserStackInFront);
@@ -2416,42 +2521,48 @@
             boolean dumpClient, String dumpPackage) {
         boolean printed = false;
         boolean needSep = false;
-        final int numStacks = mStacks.size();
-        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            StringBuilder stackHeader = new StringBuilder(128);
-            stackHeader.append("  Stack #");
-            stackHeader.append(mStacks.indexOf(stack));
-            stackHeader.append(":");
-            printed |= stack.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage, needSep,
-                    stackHeader.toString());
-            printed |= dumpHistoryList(fd, pw, stack.mLRUActivities, "    ", "Run", false, !dumpAll,
-                    false, dumpPackage, true, "    Running activities (most recent first):", null);
+        for (int displayNdx = 0; displayNdx < mDisplayInfos.size(); ++displayNdx) {
+            ActivityDisplayInfo info = mDisplayInfos.valueAt(displayNdx);
+            pw.print("Display #"); pw.println(info.mDisplayId);
+            ArrayList<ActivityStack> stacks = info.stacks;
+            final int numStacks = stacks.size();
+            for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                StringBuilder stackHeader = new StringBuilder(128);
+                stackHeader.append("  Stack #");
+                stackHeader.append(stack.mStackId);
+                stackHeader.append(":");
+                printed |= stack.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage,
+                        needSep, stackHeader.toString());
+                printed |= dumpHistoryList(fd, pw, stack.mLRUActivities, "    ", "Run", false,
+                        !dumpAll, false, dumpPackage, true,
+                        "    Running activities (most recent first):", null);
 
-            needSep = printed;
-            boolean pr = printThisActivity(pw, stack.mPausingActivity, dumpPackage, needSep,
-                    "    mPausingActivity: ");
-            if (pr) {
-                printed = true;
-                needSep = false;
-            }
-            pr = printThisActivity(pw, stack.mResumedActivity, dumpPackage, needSep,
-                    "    mResumedActivity: ");
-            if (pr) {
-                printed = true;
-                needSep = false;
-            }
-            if (dumpAll) {
-                pr = printThisActivity(pw, stack.mLastPausedActivity, dumpPackage, needSep,
-                        "    mLastPausedActivity: ");
+                needSep = printed;
+                boolean pr = printThisActivity(pw, stack.mPausingActivity, dumpPackage, needSep,
+                        "    mPausingActivity: ");
                 if (pr) {
                     printed = true;
-                    needSep = true;
+                    needSep = false;
                 }
-                printed |= printThisActivity(pw, stack.mLastNoHistoryActivity, dumpPackage,
-                        needSep, "    mLastNoHistoryActivity: ");
+                pr = printThisActivity(pw, stack.mResumedActivity, dumpPackage, needSep,
+                        "    mResumedActivity: ");
+                if (pr) {
+                    printed = true;
+                    needSep = false;
+                }
+                if (dumpAll) {
+                    pr = printThisActivity(pw, stack.mLastPausedActivity, dumpPackage, needSep,
+                            "    mLastPausedActivity: ");
+                    if (pr) {
+                        printed = true;
+                        needSep = true;
+                    }
+                    printed |= printThisActivity(pw, stack.mLastNoHistoryActivity, dumpPackage,
+                            needSep, "    mLastNoHistoryActivity: ");
+                }
+                needSep = printed;
             }
-            needSep = printed;
         }
 
         printed |= dumpHistoryList(fd, pw, mFinishingActivities, "  ", "Fin", false, !dumpAll,
@@ -2581,6 +2692,95 @@
         mHandler.sendEmptyMessageDelayed(SLEEP_TIMEOUT_MSG, SLEEP_TIMEOUT);
     }
 
+    @Override
+    public void onDisplayAdded(int displayId) {
+        mHandler.sendMessage(mHandler.obtainMessage(HANDLE_DISPLAY_ADDED, displayId, 0));
+    }
+
+    @Override
+    public void onDisplayRemoved(int displayId) {
+        mHandler.sendMessage(mHandler.obtainMessage(HANDLE_DISPLAY_REMOVED, displayId, 0));
+    }
+
+    @Override
+    public void onDisplayChanged(int displayId) {
+        mHandler.sendMessage(mHandler.obtainMessage(HANDLE_DISPLAY_CHANGED, displayId, 0));
+    }
+
+    public void handleDisplayAddedLocked(int displayId) {
+        synchronized (mService) {
+            ActivityDisplayInfo info = new ActivityDisplayInfo(displayId);
+            mDisplayInfos.put(displayId, info);
+        }
+        mWindowManager.onDisplayAdded(displayId);
+    }
+
+    public void handleDisplayRemovedLocked(int displayId) {
+        synchronized (mService) {
+            ActivityDisplayInfo info = mDisplayInfos.get(displayId);
+            if (info != null) {
+                ArrayList<ActivityStack> stacks = info.stacks;
+                for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                    info.detachActivities(stacks.get(stackNdx));
+                }
+                mDisplayInfos.remove(displayId);
+            }
+        }
+        mWindowManager.onDisplayRemoved(displayId);
+    }
+
+    public void handleDisplayChangedLocked(int displayId) {
+        synchronized (mService) {
+            ActivityDisplayInfo info = mDisplayInfos.get(displayId);
+            if (info != null) {
+                // TODO: Update the bounds.
+            }
+        }
+        mWindowManager.onDisplayChanged(displayId);
+    }
+
+    StackInfo getStackInfo(ActivityStack stack) {
+        StackInfo info = new StackInfo();
+        mWindowManager.getStackBounds(stack.mStackId, info.bounds);
+        info.displayId = Display.DEFAULT_DISPLAY;
+        info.stackId = stack.mStackId;
+
+        ArrayList<TaskRecord> tasks = stack.getAllTasks();
+        final int numTasks = tasks.size();
+        int[] taskIds = new int[numTasks];
+        String[] taskNames = new String[numTasks];
+        for (int i = 0; i < numTasks; ++i) {
+            final TaskRecord task = tasks.get(i);
+            taskIds[i] = task.taskId;
+            taskNames[i] = task.origActivity != null ? task.origActivity.flattenToString()
+                    : task.realActivity != null ? task.realActivity.flattenToString()
+                    : task.getTopActivity() != null ? task.getTopActivity().packageName
+                    : "unknown";
+        }
+        info.taskIds = taskIds;
+        info.taskNames = taskNames;
+        return info;
+    }
+
+    StackInfo getStackInfoLocked(int stackId) {
+        ActivityStack stack = getStack(stackId);
+        if (stack != null) {
+            return getStackInfo(stack);
+        }
+        return null;
+    }
+
+    ArrayList<StackInfo> getAllStackInfosLocked() {
+        ArrayList<StackInfo> list = new ArrayList<StackInfo>();
+        for (int displayNdx = 0; displayNdx < mDisplayInfos.size(); ++displayNdx) {
+            ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks;
+            for (int ndx = stacks.size() - 1; ndx >= 0; --ndx) {
+                list.add(getStackInfo(stacks.get(ndx)));
+            }
+        }
+        return list;
+    }
+
     private final class ActivityStackSupervisorHandler extends Handler {
 
         public ActivityStackSupervisorHandler(Looper looper) {
@@ -2644,7 +2844,131 @@
                         }
                     }
                 } break;
+                case HANDLE_DISPLAY_ADDED: {
+                    handleDisplayAddedLocked(msg.arg1);
+                } break;
+                case HANDLE_DISPLAY_CHANGED: {
+                    handleDisplayChangedLocked(msg.arg1);
+                } break;
+                case HANDLE_DISPLAY_REMOVED: {
+                    handleDisplayRemovedLocked(msg.arg1);
+                } break;
             }
         }
     }
+
+    class ActivityContainer extends IActivityContainer.Stub {
+        final int mStackId;
+        final IActivityContainerCallback mCallback;
+        final ActivityStack mStack;
+        final ActivityRecord mParentActivity;
+
+        /** Display this ActivityStack is currently on. Null if not attached to a Display. */
+        ActivityDisplayInfo mActivityDisplayInfo;
+
+        ActivityContainer(ActivityRecord parentActivity, int stackId,
+                IActivityContainerCallback callback) {
+            synchronized (mService) {
+                mStackId = stackId;
+                mStack = new ActivityStack(this);
+                mParentActivity = parentActivity;
+                mCallback = callback;
+            }
+        }
+
+        void attachToDisplayLocked(ActivityDisplayInfo displayInfo) {
+            mActivityDisplayInfo = displayInfo;
+            displayInfo.attachActivities(mStack);
+            mWindowManager.createStack(mStackId, displayInfo.mDisplayId);
+        }
+
+        @Override
+        public void attachToDisplay(int displayId) throws RemoteException {
+            synchronized (mService) {
+                ActivityDisplayInfo displayInfo = mDisplayInfos.get(displayId);
+                if (displayInfo == null) {
+                    return;
+                }
+                attachToDisplayLocked(displayInfo);
+            }
+        }
+
+        @Override
+        public int getStackId() throws RemoteException {
+            return mStack.mStackId;
+        }
+
+        void detachLocked() {
+            if (mActivityDisplayInfo != null) {
+                mActivityDisplayInfo.detachActivities(mStack);
+                mActivityDisplayInfo = null;
+            }
+        }
+
+        @Override
+        public void detachFromDisplay() throws RemoteException {
+            synchronized (mService) {
+                detachLocked();
+            }
+        }
+
+        @Override
+        public void startActivity(Intent intent) throws RemoteException {
+
+        }
+
+        @Override
+        public IBinder asBinder() {
+            return this;
+        }
+
+        ActivityStackSupervisor getOuter() {
+            return ActivityStackSupervisor.this;
+        }
+
+        boolean isAttached() {
+            return mActivityDisplayInfo != null;
+        }
+
+        void getBounds(Point outBounds) {
+            if (mActivityDisplayInfo != null) {
+                mActivityDisplayInfo.getBounds(outBounds);
+            } else {
+                outBounds.set(0, 0);
+            }
+        }
+    }
+
+    /** Exactly one of these classes per Display in the system. Capable of holding zero or more
+     * attached {@link ActivityStack}s */
+    final class ActivityDisplayInfo {
+        /** Actual Display this object tracks. */
+        final int mDisplayId;
+        final Display mDisplay;
+        final DisplayInfo mDisplayInfo = new DisplayInfo();
+
+        /** All of the stacks on this display. Order matters, topmost stack is in front of all other
+         * stacks, bottommost behind. Accessed directly by ActivityManager package classes */
+        final ArrayList<ActivityStack> stacks = new ArrayList<ActivityStack>();
+
+        ActivityDisplayInfo(int displayId) {
+            mDisplayId = displayId;
+            mDisplay = mDisplayManager.getDisplay(displayId);
+            mDisplay.getDisplayInfo(mDisplayInfo);
+        }
+
+        void attachActivities(ActivityStack stack) {
+            stacks.add(stack);
+        }
+
+        void detachActivities(ActivityStack stack) {
+            stacks.remove(stack);
+        }
+
+        void getBounds(Point bounds) {
+            mDisplay.getDisplayInfo(mDisplayInfo);
+            bounds.x = mDisplayInfo.appWidth;
+            bounds.y = mDisplayInfo.appHeight;
+        }
+    }
 }
diff --git a/services/java/com/android/server/am/AppBindRecord.java b/services/core/java/com/android/server/am/AppBindRecord.java
similarity index 100%
rename from services/java/com/android/server/am/AppBindRecord.java
rename to services/core/java/com/android/server/am/AppBindRecord.java
diff --git a/services/java/com/android/server/am/AppErrorDialog.java b/services/core/java/com/android/server/am/AppErrorDialog.java
similarity index 100%
rename from services/java/com/android/server/am/AppErrorDialog.java
rename to services/core/java/com/android/server/am/AppErrorDialog.java
diff --git a/services/java/com/android/server/am/AppErrorResult.java b/services/core/java/com/android/server/am/AppErrorResult.java
similarity index 100%
rename from services/java/com/android/server/am/AppErrorResult.java
rename to services/core/java/com/android/server/am/AppErrorResult.java
diff --git a/services/java/com/android/server/am/AppNotRespondingDialog.java b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
similarity index 100%
rename from services/java/com/android/server/am/AppNotRespondingDialog.java
rename to services/core/java/com/android/server/am/AppNotRespondingDialog.java
diff --git a/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java b/services/core/java/com/android/server/am/AppWaitingForDebuggerDialog.java
similarity index 100%
rename from services/java/com/android/server/am/AppWaitingForDebuggerDialog.java
rename to services/core/java/com/android/server/am/AppWaitingForDebuggerDialog.java
diff --git a/services/java/com/android/server/am/BackupRecord.java b/services/core/java/com/android/server/am/BackupRecord.java
similarity index 100%
rename from services/java/com/android/server/am/BackupRecord.java
rename to services/core/java/com/android/server/am/BackupRecord.java
diff --git a/services/java/com/android/server/am/BaseErrorDialog.java b/services/core/java/com/android/server/am/BaseErrorDialog.java
similarity index 100%
rename from services/java/com/android/server/am/BaseErrorDialog.java
rename to services/core/java/com/android/server/am/BaseErrorDialog.java
diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
similarity index 100%
rename from services/java/com/android/server/am/BatteryStatsService.java
rename to services/core/java/com/android/server/am/BatteryStatsService.java
diff --git a/services/java/com/android/server/am/BroadcastFilter.java b/services/core/java/com/android/server/am/BroadcastFilter.java
similarity index 100%
rename from services/java/com/android/server/am/BroadcastFilter.java
rename to services/core/java/com/android/server/am/BroadcastFilter.java
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
similarity index 100%
rename from services/java/com/android/server/am/BroadcastQueue.java
rename to services/core/java/com/android/server/am/BroadcastQueue.java
diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
similarity index 100%
rename from services/java/com/android/server/am/BroadcastRecord.java
rename to services/core/java/com/android/server/am/BroadcastRecord.java
diff --git a/services/java/com/android/server/am/CompatModeDialog.java b/services/core/java/com/android/server/am/CompatModeDialog.java
similarity index 100%
rename from services/java/com/android/server/am/CompatModeDialog.java
rename to services/core/java/com/android/server/am/CompatModeDialog.java
diff --git a/services/java/com/android/server/am/CompatModePackages.java b/services/core/java/com/android/server/am/CompatModePackages.java
similarity index 100%
rename from services/java/com/android/server/am/CompatModePackages.java
rename to services/core/java/com/android/server/am/CompatModePackages.java
diff --git a/services/java/com/android/server/am/ConnectionRecord.java b/services/core/java/com/android/server/am/ConnectionRecord.java
similarity index 100%
rename from services/java/com/android/server/am/ConnectionRecord.java
rename to services/core/java/com/android/server/am/ConnectionRecord.java
diff --git a/services/java/com/android/server/am/ContentProviderConnection.java b/services/core/java/com/android/server/am/ContentProviderConnection.java
similarity index 100%
rename from services/java/com/android/server/am/ContentProviderConnection.java
rename to services/core/java/com/android/server/am/ContentProviderConnection.java
diff --git a/services/java/com/android/server/am/ContentProviderRecord.java b/services/core/java/com/android/server/am/ContentProviderRecord.java
similarity index 100%
rename from services/java/com/android/server/am/ContentProviderRecord.java
rename to services/core/java/com/android/server/am/ContentProviderRecord.java
diff --git a/services/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
similarity index 100%
rename from services/java/com/android/server/am/CoreSettingsObserver.java
rename to services/core/java/com/android/server/am/CoreSettingsObserver.java
diff --git a/services/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
similarity index 100%
rename from services/java/com/android/server/am/EventLogTags.logtags
rename to services/core/java/com/android/server/am/EventLogTags.logtags
diff --git a/services/java/com/android/server/am/FactoryErrorDialog.java b/services/core/java/com/android/server/am/FactoryErrorDialog.java
similarity index 100%
rename from services/java/com/android/server/am/FactoryErrorDialog.java
rename to services/core/java/com/android/server/am/FactoryErrorDialog.java
diff --git a/services/java/com/android/server/am/IntentBindRecord.java b/services/core/java/com/android/server/am/IntentBindRecord.java
similarity index 100%
rename from services/java/com/android/server/am/IntentBindRecord.java
rename to services/core/java/com/android/server/am/IntentBindRecord.java
diff --git a/services/java/com/android/server/am/LaunchWarningWindow.java b/services/core/java/com/android/server/am/LaunchWarningWindow.java
similarity index 100%
rename from services/java/com/android/server/am/LaunchWarningWindow.java
rename to services/core/java/com/android/server/am/LaunchWarningWindow.java
diff --git a/services/java/com/android/server/am/NativeCrashListener.java b/services/core/java/com/android/server/am/NativeCrashListener.java
similarity index 100%
rename from services/java/com/android/server/am/NativeCrashListener.java
rename to services/core/java/com/android/server/am/NativeCrashListener.java
diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
similarity index 100%
rename from services/java/com/android/server/am/PendingIntentRecord.java
rename to services/core/java/com/android/server/am/PendingIntentRecord.java
diff --git a/services/java/com/android/server/am/PendingThumbnailsRecord.java b/services/core/java/com/android/server/am/PendingThumbnailsRecord.java
similarity index 100%
rename from services/java/com/android/server/am/PendingThumbnailsRecord.java
rename to services/core/java/com/android/server/am/PendingThumbnailsRecord.java
diff --git a/services/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
similarity index 100%
rename from services/java/com/android/server/am/ProcessList.java
rename to services/core/java/com/android/server/am/ProcessList.java
diff --git a/services/java/com/android/server/am/ProcessMemInfo.java b/services/core/java/com/android/server/am/ProcessMemInfo.java
similarity index 100%
rename from services/java/com/android/server/am/ProcessMemInfo.java
rename to services/core/java/com/android/server/am/ProcessMemInfo.java
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
similarity index 100%
rename from services/java/com/android/server/am/ProcessRecord.java
rename to services/core/java/com/android/server/am/ProcessRecord.java
diff --git a/services/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java
similarity index 100%
rename from services/java/com/android/server/am/ProcessStatsService.java
rename to services/core/java/com/android/server/am/ProcessStatsService.java
diff --git a/services/java/com/android/server/am/ProviderMap.java b/services/core/java/com/android/server/am/ProviderMap.java
similarity index 100%
rename from services/java/com/android/server/am/ProviderMap.java
rename to services/core/java/com/android/server/am/ProviderMap.java
diff --git a/services/java/com/android/server/am/ReceiverList.java b/services/core/java/com/android/server/am/ReceiverList.java
similarity index 100%
rename from services/java/com/android/server/am/ReceiverList.java
rename to services/core/java/com/android/server/am/ReceiverList.java
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
similarity index 98%
rename from services/java/com/android/server/am/ServiceRecord.java
rename to services/core/java/com/android/server/am/ServiceRecord.java
index 80e6e94..cb04835 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -18,7 +18,8 @@
 
 import com.android.internal.app.ProcessStats;
 import com.android.internal.os.BatteryStatsImpl;
-import com.android.server.NotificationManagerService;
+import com.android.server.LocalServices;
+import com.android.server.notification.NotificationManagerInternal;
 
 import android.app.INotificationManager;
 import android.app.Notification;
@@ -427,8 +428,8 @@
             final Notification localForegroundNoti = foregroundNoti;
             ams.mHandler.post(new Runnable() {
                 public void run() {
-                    NotificationManagerService nm =
-                            (NotificationManagerService) NotificationManager.getService();
+                    NotificationManagerInternal nm = LocalServices.getService(
+                            NotificationManagerInternal.class);
                     if (nm == null) {
                         return;
                     }
@@ -479,7 +480,7 @@
                             throw new RuntimeException("icon must be non-zero");
                         }
                         int[] outId = new int[1];
-                        nm.enqueueNotificationInternal(localPackageName, localPackageName,
+                        nm.enqueueNotification(localPackageName, localPackageName,
                                 appUid, appPid, null, localForegroundId, localForegroundNoti,
                                 outId, userId);
                     } catch (RuntimeException e) {
diff --git a/services/java/com/android/server/am/StrictModeViolationDialog.java b/services/core/java/com/android/server/am/StrictModeViolationDialog.java
similarity index 100%
rename from services/java/com/android/server/am/StrictModeViolationDialog.java
rename to services/core/java/com/android/server/am/StrictModeViolationDialog.java
diff --git a/services/java/com/android/server/am/TaskAccessInfo.java b/services/core/java/com/android/server/am/TaskAccessInfo.java
similarity index 100%
rename from services/java/com/android/server/am/TaskAccessInfo.java
rename to services/core/java/com/android/server/am/TaskAccessInfo.java
diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
similarity index 96%
rename from services/java/com/android/server/am/TaskRecord.java
rename to services/core/java/com/android/server/am/TaskRecord.java
index 3d568ff..9105103 100644
--- a/services/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -159,18 +159,33 @@
         return null;
     }
 
+    /** Call after activity movement or finish to make sure that frontOfTask is set correctly */
+    final void setFrontOfTask() {
+        boolean foundFront = false;
+        final int numActivities = mActivities.size();
+        for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
+            final ActivityRecord r = mActivities.get(activityNdx);
+            if (foundFront || r.finishing) {
+                r.frontOfTask = false;
+            } else {
+                r.frontOfTask = true;
+                // Set frontOfTask false for every following activity.
+                foundFront = true;
+            }
+        }
+    }
+
     /**
-     * Reorder the history stack so that the activity at the given index is
-     * brought to the front.
+     * Reorder the history stack so that the passed activity is brought to the front.
      */
     final void moveActivityToFrontLocked(ActivityRecord newTop) {
         if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Removing and adding activity " + newTop
             + " to stack at top", new RuntimeException("here").fillInStackTrace());
 
-        getTopActivity().frontOfTask = false;
         mActivities.remove(newTop);
         mActivities.add(newTop);
-        newTop.frontOfTask = true;
+
+        setFrontOfTask();
     }
 
     void addActivityAtBottom(ActivityRecord r) {
diff --git a/services/java/com/android/server/am/ThumbnailHolder.java b/services/core/java/com/android/server/am/ThumbnailHolder.java
similarity index 100%
rename from services/java/com/android/server/am/ThumbnailHolder.java
rename to services/core/java/com/android/server/am/ThumbnailHolder.java
diff --git a/services/java/com/android/server/am/UriPermission.java b/services/core/java/com/android/server/am/UriPermission.java
similarity index 100%
rename from services/java/com/android/server/am/UriPermission.java
rename to services/core/java/com/android/server/am/UriPermission.java
diff --git a/services/java/com/android/server/am/UriPermissionOwner.java b/services/core/java/com/android/server/am/UriPermissionOwner.java
similarity index 100%
rename from services/java/com/android/server/am/UriPermissionOwner.java
rename to services/core/java/com/android/server/am/UriPermissionOwner.java
diff --git a/services/java/com/android/server/am/UsageStatsService.java b/services/core/java/com/android/server/am/UsageStatsService.java
similarity index 100%
rename from services/java/com/android/server/am/UsageStatsService.java
rename to services/core/java/com/android/server/am/UsageStatsService.java
diff --git a/services/java/com/android/server/am/UserStartedState.java b/services/core/java/com/android/server/am/UserStartedState.java
similarity index 100%
rename from services/java/com/android/server/am/UserStartedState.java
rename to services/core/java/com/android/server/am/UserStartedState.java
diff --git a/services/java/com/android/server/am/package.html b/services/core/java/com/android/server/am/package.html
similarity index 100%
rename from services/java/com/android/server/am/package.html
rename to services/core/java/com/android/server/am/package.html
diff --git a/services/java/com/android/server/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
similarity index 99%
rename from services/java/com/android/server/ClipboardService.java
rename to services/core/java/com/android/server/clipboard/ClipboardService.java
index 069ae23..6aa596d 100644
--- a/services/java/com/android/server/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.clipboard;
 
 import android.app.ActivityManagerNative;
 import android.app.AppGlobals;
diff --git a/services/java/com/android/server/connectivity/DataConnectionStats.java b/services/core/java/com/android/server/connectivity/DataConnectionStats.java
similarity index 100%
rename from services/java/com/android/server/connectivity/DataConnectionStats.java
rename to services/core/java/com/android/server/connectivity/DataConnectionStats.java
diff --git a/services/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
similarity index 100%
rename from services/java/com/android/server/connectivity/Nat464Xlat.java
rename to services/core/java/com/android/server/connectivity/Nat464Xlat.java
diff --git a/services/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
similarity index 100%
rename from services/java/com/android/server/connectivity/PacManager.java
rename to services/core/java/com/android/server/connectivity/PacManager.java
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
similarity index 100%
rename from services/java/com/android/server/connectivity/Tethering.java
rename to services/core/java/com/android/server/connectivity/Tethering.java
diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
similarity index 100%
rename from services/java/com/android/server/connectivity/Vpn.java
rename to services/core/java/com/android/server/connectivity/Vpn.java
diff --git a/services/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
similarity index 100%
rename from services/java/com/android/server/content/ContentService.java
rename to services/core/java/com/android/server/content/ContentService.java
diff --git a/services/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
similarity index 100%
rename from services/java/com/android/server/content/SyncManager.java
rename to services/core/java/com/android/server/content/SyncManager.java
diff --git a/services/java/com/android/server/content/SyncOperation.java b/services/core/java/com/android/server/content/SyncOperation.java
similarity index 100%
rename from services/java/com/android/server/content/SyncOperation.java
rename to services/core/java/com/android/server/content/SyncOperation.java
diff --git a/services/java/com/android/server/content/SyncQueue.java b/services/core/java/com/android/server/content/SyncQueue.java
similarity index 100%
rename from services/java/com/android/server/content/SyncQueue.java
rename to services/core/java/com/android/server/content/SyncQueue.java
diff --git a/services/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
similarity index 100%
rename from services/java/com/android/server/content/SyncStorageEngine.java
rename to services/core/java/com/android/server/content/SyncStorageEngine.java
diff --git a/services/java/com/android/server/display/DisplayAdapter.java b/services/core/java/com/android/server/display/DisplayAdapter.java
similarity index 100%
rename from services/java/com/android/server/display/DisplayAdapter.java
rename to services/core/java/com/android/server/display/DisplayAdapter.java
diff --git a/services/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
similarity index 100%
rename from services/java/com/android/server/display/DisplayDevice.java
rename to services/core/java/com/android/server/display/DisplayDevice.java
diff --git a/services/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
similarity index 100%
rename from services/java/com/android/server/display/DisplayDeviceInfo.java
rename to services/core/java/com/android/server/display/DisplayDeviceInfo.java
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
similarity index 98%
rename from services/java/com/android/server/display/DisplayManagerService.java
rename to services/core/java/com/android/server/display/DisplayManagerService.java
index bcb677f..73040d5 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -102,7 +102,6 @@
     // Otherwise WFD is enabled according to the value of config_enableWifiDisplay.
     private static final String FORCE_WIFI_DISPLAY_ENABLE = "persist.debug.wfd.enable";
 
-    private static final String SYSTEM_HEADLESS = "ro.config.headless";
     private static final long WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT = 10000;
 
     private static final int MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER = 1;
@@ -116,7 +115,6 @@
     private static final int DISPLAY_BLANK_STATE_UNBLANKED = 2;
 
     private final Context mContext;
-    private final boolean mHeadless;
     private final DisplayManagerHandler mHandler;
     private final Handler mUiHandler;
     private final DisplayAdapterListener mDisplayAdapterListener;
@@ -202,8 +200,6 @@
 
     public DisplayManagerService(Context context, Handler mainHandler) {
         mContext = context;
-        mHeadless = SystemProperties.get(SYSTEM_HEADLESS).equals("1");
-
         mHandler = new DisplayManagerHandler(mainHandler.getLooper());
         mUiHandler = UiThread.getHandler();
         mDisplayAdapterListener = new DisplayAdapterListener();
@@ -270,15 +266,6 @@
     }
 
     /**
-     * Returns true if the device is headless.
-     *
-     * @return True if the device is headless.
-     */
-    public boolean isHeadless() {
-        return mHeadless;
-    }
-
-    /**
      * Registers a display transaction listener to provide the client a chance to
      * update its surfaces within the same transaction as any display layout updates.
      *
@@ -779,13 +766,8 @@
     private void registerDefaultDisplayAdapter() {
         // Register default display adapter.
         synchronized (mSyncRoot) {
-            if (mHeadless) {
-                registerDisplayAdapterLocked(new HeadlessDisplayAdapter(
-                        mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
-            } else {
-                registerDisplayAdapterLocked(new LocalDisplayAdapter(
-                        mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
-            }
+            registerDisplayAdapterLocked(new LocalDisplayAdapter(
+                    mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
         }
     }
 
@@ -1153,7 +1135,6 @@
         pw.println("DISPLAY MANAGER (dumpsys display)");
 
         synchronized (mSyncRoot) {
-            pw.println("  mHeadless=" + mHeadless);
             pw.println("  mOnlyCode=" + mOnlyCore);
             pw.println("  mSafeMode=" + mSafeMode);
             pw.println("  mPendingTraversal=" + mPendingTraversal);
diff --git a/services/java/com/android/server/display/DisplayTransactionListener.java b/services/core/java/com/android/server/display/DisplayTransactionListener.java
similarity index 100%
rename from services/java/com/android/server/display/DisplayTransactionListener.java
rename to services/core/java/com/android/server/display/DisplayTransactionListener.java
diff --git a/services/java/com/android/server/display/DisplayViewport.java b/services/core/java/com/android/server/display/DisplayViewport.java
similarity index 100%
rename from services/java/com/android/server/display/DisplayViewport.java
rename to services/core/java/com/android/server/display/DisplayViewport.java
diff --git a/services/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
similarity index 100%
rename from services/java/com/android/server/display/LocalDisplayAdapter.java
rename to services/core/java/com/android/server/display/LocalDisplayAdapter.java
diff --git a/services/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
similarity index 100%
rename from services/java/com/android/server/display/LogicalDisplay.java
rename to services/core/java/com/android/server/display/LogicalDisplay.java
diff --git a/services/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
similarity index 100%
rename from services/java/com/android/server/display/OverlayDisplayAdapter.java
rename to services/core/java/com/android/server/display/OverlayDisplayAdapter.java
diff --git a/services/java/com/android/server/display/OverlayDisplayWindow.java b/services/core/java/com/android/server/display/OverlayDisplayWindow.java
similarity index 100%
rename from services/java/com/android/server/display/OverlayDisplayWindow.java
rename to services/core/java/com/android/server/display/OverlayDisplayWindow.java
diff --git a/services/java/com/android/server/display/PersistentDataStore.java b/services/core/java/com/android/server/display/PersistentDataStore.java
similarity index 100%
rename from services/java/com/android/server/display/PersistentDataStore.java
rename to services/core/java/com/android/server/display/PersistentDataStore.java
diff --git a/services/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
similarity index 100%
rename from services/java/com/android/server/display/VirtualDisplayAdapter.java
rename to services/core/java/com/android/server/display/VirtualDisplayAdapter.java
diff --git a/services/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
similarity index 100%
rename from services/java/com/android/server/display/WifiDisplayAdapter.java
rename to services/core/java/com/android/server/display/WifiDisplayAdapter.java
diff --git a/services/java/com/android/server/display/WifiDisplayController.java b/services/core/java/com/android/server/display/WifiDisplayController.java
similarity index 100%
rename from services/java/com/android/server/display/WifiDisplayController.java
rename to services/core/java/com/android/server/display/WifiDisplayController.java
diff --git a/services/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java
similarity index 100%
rename from services/java/com/android/server/dreams/DreamController.java
rename to services/core/java/com/android/server/dreams/DreamController.java
diff --git a/services/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
similarity index 100%
rename from services/java/com/android/server/dreams/DreamManagerService.java
rename to services/core/java/com/android/server/dreams/DreamManagerService.java
diff --git a/services/java/com/android/server/firewall/AndFilter.java b/services/core/java/com/android/server/firewall/AndFilter.java
similarity index 100%
rename from services/java/com/android/server/firewall/AndFilter.java
rename to services/core/java/com/android/server/firewall/AndFilter.java
diff --git a/services/java/com/android/server/firewall/CategoryFilter.java b/services/core/java/com/android/server/firewall/CategoryFilter.java
similarity index 100%
rename from services/java/com/android/server/firewall/CategoryFilter.java
rename to services/core/java/com/android/server/firewall/CategoryFilter.java
diff --git a/services/java/com/android/server/firewall/Filter.java b/services/core/java/com/android/server/firewall/Filter.java
similarity index 100%
rename from services/java/com/android/server/firewall/Filter.java
rename to services/core/java/com/android/server/firewall/Filter.java
diff --git a/services/java/com/android/server/firewall/FilterFactory.java b/services/core/java/com/android/server/firewall/FilterFactory.java
similarity index 100%
rename from services/java/com/android/server/firewall/FilterFactory.java
rename to services/core/java/com/android/server/firewall/FilterFactory.java
diff --git a/services/java/com/android/server/firewall/FilterList.java b/services/core/java/com/android/server/firewall/FilterList.java
similarity index 100%
rename from services/java/com/android/server/firewall/FilterList.java
rename to services/core/java/com/android/server/firewall/FilterList.java
diff --git a/services/java/com/android/server/firewall/IntentFirewall.java b/services/core/java/com/android/server/firewall/IntentFirewall.java
similarity index 100%
rename from services/java/com/android/server/firewall/IntentFirewall.java
rename to services/core/java/com/android/server/firewall/IntentFirewall.java
diff --git a/services/java/com/android/server/firewall/NotFilter.java b/services/core/java/com/android/server/firewall/NotFilter.java
similarity index 100%
rename from services/java/com/android/server/firewall/NotFilter.java
rename to services/core/java/com/android/server/firewall/NotFilter.java
diff --git a/services/java/com/android/server/firewall/OrFilter.java b/services/core/java/com/android/server/firewall/OrFilter.java
similarity index 100%
rename from services/java/com/android/server/firewall/OrFilter.java
rename to services/core/java/com/android/server/firewall/OrFilter.java
diff --git a/services/java/com/android/server/firewall/PortFilter.java b/services/core/java/com/android/server/firewall/PortFilter.java
similarity index 100%
rename from services/java/com/android/server/firewall/PortFilter.java
rename to services/core/java/com/android/server/firewall/PortFilter.java
diff --git a/services/java/com/android/server/firewall/SenderFilter.java b/services/core/java/com/android/server/firewall/SenderFilter.java
similarity index 100%
rename from services/java/com/android/server/firewall/SenderFilter.java
rename to services/core/java/com/android/server/firewall/SenderFilter.java
diff --git a/services/java/com/android/server/firewall/SenderPermissionFilter.java b/services/core/java/com/android/server/firewall/SenderPermissionFilter.java
similarity index 100%
rename from services/java/com/android/server/firewall/SenderPermissionFilter.java
rename to services/core/java/com/android/server/firewall/SenderPermissionFilter.java
diff --git a/services/java/com/android/server/firewall/StringFilter.java b/services/core/java/com/android/server/firewall/StringFilter.java
similarity index 100%
rename from services/java/com/android/server/firewall/StringFilter.java
rename to services/core/java/com/android/server/firewall/StringFilter.java
diff --git a/services/java/com/android/server/input/InputApplicationHandle.java b/services/core/java/com/android/server/input/InputApplicationHandle.java
similarity index 100%
rename from services/java/com/android/server/input/InputApplicationHandle.java
rename to services/core/java/com/android/server/input/InputApplicationHandle.java
diff --git a/services/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
similarity index 100%
rename from services/java/com/android/server/input/InputManagerService.java
rename to services/core/java/com/android/server/input/InputManagerService.java
diff --git a/services/java/com/android/server/input/InputWindowHandle.java b/services/core/java/com/android/server/input/InputWindowHandle.java
similarity index 100%
rename from services/java/com/android/server/input/InputWindowHandle.java
rename to services/core/java/com/android/server/input/InputWindowHandle.java
diff --git a/services/java/com/android/server/input/PersistentDataStore.java b/services/core/java/com/android/server/input/PersistentDataStore.java
similarity index 100%
rename from services/java/com/android/server/input/PersistentDataStore.java
rename to services/core/java/com/android/server/input/PersistentDataStore.java
diff --git a/services/core/java/com/android/server/lights/Light.java b/services/core/java/com/android/server/lights/Light.java
new file mode 100644
index 0000000..b496b4c6
--- /dev/null
+++ b/services/core/java/com/android/server/lights/Light.java
@@ -0,0 +1,41 @@
+/*
+ * 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.lights;
+
+public abstract class Light {
+    public static final int LIGHT_FLASH_NONE = 0;
+    public static final int LIGHT_FLASH_TIMED = 1;
+    public static final int LIGHT_FLASH_HARDWARE = 2;
+
+    /**
+     * Light brightness is managed by a user setting.
+     */
+    public static final int BRIGHTNESS_MODE_USER = 0;
+
+    /**
+     * Light brightness is managed by a light sensor.
+     */
+    public static final int BRIGHTNESS_MODE_SENSOR = 1;
+
+    public abstract void setBrightness(int brightness);
+    public abstract void setBrightness(int brightness, int brightnessMode);
+    public abstract void setColor(int color);
+    public abstract void setFlashing(int color, int mode, int onMS, int offMS);
+    public abstract void pulse();
+    public abstract void pulse(int color, int onMS);
+    public abstract void turnOff();
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/lights/LightsManager.java b/services/core/java/com/android/server/lights/LightsManager.java
new file mode 100644
index 0000000..2f20509
--- /dev/null
+++ b/services/core/java/com/android/server/lights/LightsManager.java
@@ -0,0 +1,31 @@
+/*
+ * 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.lights;
+
+public abstract class LightsManager {
+    public static final int LIGHT_ID_BACKLIGHT = 0;
+    public static final int LIGHT_ID_KEYBOARD = 1;
+    public static final int LIGHT_ID_BUTTONS = 2;
+    public static final int LIGHT_ID_BATTERY = 3;
+    public static final int LIGHT_ID_NOTIFICATIONS = 4;
+    public static final int LIGHT_ID_ATTENTION = 5;
+    public static final int LIGHT_ID_BLUETOOTH = 6;
+    public static final int LIGHT_ID_WIFI = 7;
+    public static final int LIGHT_ID_COUNT = 8;
+
+    public abstract Light getLight(int id);
+}
diff --git a/services/java/com/android/server/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
similarity index 73%
rename from services/java/com/android/server/LightsService.java
rename to services/core/java/com/android/server/lights/LightsService.java
index 89bfcac..d814785 100644
--- a/services/java/com/android/server/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -14,59 +14,38 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.lights;
+
+import com.android.server.SystemService;
 
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Handler;
 import android.os.IHardwareService;
-import android.os.ServiceManager;
 import android.os.Message;
 import android.util.Slog;
 
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 
-public class LightsService {
-    private static final String TAG = "LightsService";
-    private static final boolean DEBUG = false;
+public class LightsService extends SystemService {
+    static final String TAG = "LightsService";
+    static final boolean DEBUG = false;
 
-    public static final int LIGHT_ID_BACKLIGHT = 0;
-    public static final int LIGHT_ID_KEYBOARD = 1;
-    public static final int LIGHT_ID_BUTTONS = 2;
-    public static final int LIGHT_ID_BATTERY = 3;
-    public static final int LIGHT_ID_NOTIFICATIONS = 4;
-    public static final int LIGHT_ID_ATTENTION = 5;
-    public static final int LIGHT_ID_BLUETOOTH = 6;
-    public static final int LIGHT_ID_WIFI = 7;
-    public static final int LIGHT_ID_COUNT = 8;
+    final LightImpl mLights[] = new LightImpl[LightsManager.LIGHT_ID_COUNT];
 
-    public static final int LIGHT_FLASH_NONE = 0;
-    public static final int LIGHT_FLASH_TIMED = 1;
-    public static final int LIGHT_FLASH_HARDWARE = 2;
+    private final class LightImpl extends Light {
 
-    /**
-     * Light brightness is managed by a user setting.
-     */
-    public static final int BRIGHTNESS_MODE_USER = 0;
-
-    /**
-     * Light brightness is managed by a light sensor.
-     */
-    public static final int BRIGHTNESS_MODE_SENSOR = 1;
-
-    private final Light mLights[] = new Light[LIGHT_ID_COUNT];
-
-    public final class Light {
-
-        private Light(int id) {
+        private LightImpl(int id) {
             mId = id;
         }
 
+        @Override
         public void setBrightness(int brightness) {
             setBrightness(brightness, BRIGHTNESS_MODE_USER);
         }
 
+        @Override
         public void setBrightness(int brightness, int brightnessMode) {
             synchronized (this) {
                 int color = brightness & 0x000000ff;
@@ -75,23 +54,26 @@
             }
         }
 
+        @Override
         public void setColor(int color) {
             synchronized (this) {
                 setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, 0);
             }
         }
 
+        @Override
         public void setFlashing(int color, int mode, int onMS, int offMS) {
             synchronized (this) {
                 setLightLocked(color, mode, onMS, offMS, BRIGHTNESS_MODE_USER);
             }
         }
 
-
+        @Override
         public void pulse() {
             pulse(0x00ffffff, 7);
         }
 
+        @Override
         public void pulse(int color, int onMS) {
             synchronized (this) {
                 if (mColor == 0 && !mFlashing) {
@@ -101,6 +83,7 @@
             }
         }
 
+        @Override
         public void turnOff() {
             synchronized (this) {
                 setLightLocked(0, LIGHT_FLASH_NONE, 0, 0, 0);
@@ -153,9 +136,10 @@
         }
 
         public void setFlashlightEnabled(boolean on) {
-            if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.FLASHLIGHT)
+            final Context context = getContext();
+            if (context.checkCallingOrSelfPermission(android.Manifest.permission.FLASHLIGHT)
                     != PackageManager.PERMISSION_GRANTED &&
-                    mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
+                    context.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
                     != PackageManager.PERMISSION_GRANTED) {
                 throw new SecurityException("Requires FLASHLIGHT or HARDWARE_TEST permission");
             }
@@ -172,31 +156,41 @@
         }
     };
 
-    LightsService(Context context) {
-
+    @Override
+    public void onCreate(Context context) {
         mNativePointer = init_native();
-        mContext = context;
 
-        ServiceManager.addService("hardware", mLegacyFlashlightHack);
-
-        for (int i = 0; i < LIGHT_ID_COUNT; i++) {
-            mLights[i] = new Light(i);
+        for (int i = 0; i < LightsManager.LIGHT_ID_COUNT; i++) {
+            mLights[i] = new LightImpl(i);
         }
     }
 
+    @Override
+    public void onStart() {
+        publishBinderService("hardware", mLegacyFlashlightHack);
+        publishLocalService(LightsManager.class, mService);
+    }
+
+    private final LightsManager mService = new LightsManager() {
+        @Override
+        public com.android.server.lights.Light getLight(int id) {
+            if (id < LIGHT_ID_COUNT) {
+                return mLights[id];
+            } else {
+                return null;
+            }
+        }
+    };
+
     protected void finalize() throws Throwable {
         finalize_native(mNativePointer);
         super.finalize();
     }
 
-    public Light getLight(int id) {
-        return mLights[id];
-    }
-
     private Handler mH = new Handler() {
         @Override
         public void handleMessage(Message msg) {
-            Light light = (Light)msg.obj;
+            LightImpl light = (LightImpl)msg.obj;
             light.stopFlashing();
         }
     };
@@ -204,10 +198,8 @@
     private static native int init_native();
     private static native void finalize_native(int ptr);
 
-    private static native void setLight_native(int ptr, int light, int color, int mode,
+    static native void setLight_native(int ptr, int light, int color, int mode,
             int onMS, int offMS, int brightnessMode);
 
-    private final Context mContext;
-
-    private int mNativePointer;
+    int mNativePointer;
 }
diff --git a/services/java/com/android/server/location/ComprehensiveCountryDetector.java b/services/core/java/com/android/server/location/ComprehensiveCountryDetector.java
similarity index 100%
rename from services/java/com/android/server/location/ComprehensiveCountryDetector.java
rename to services/core/java/com/android/server/location/ComprehensiveCountryDetector.java
diff --git a/services/java/com/android/server/location/CountryDetectorBase.java b/services/core/java/com/android/server/location/CountryDetectorBase.java
similarity index 100%
rename from services/java/com/android/server/location/CountryDetectorBase.java
rename to services/core/java/com/android/server/location/CountryDetectorBase.java
diff --git a/services/java/com/android/server/location/FlpHardwareProvider.java b/services/core/java/com/android/server/location/FlpHardwareProvider.java
similarity index 100%
rename from services/java/com/android/server/location/FlpHardwareProvider.java
rename to services/core/java/com/android/server/location/FlpHardwareProvider.java
diff --git a/services/java/com/android/server/location/FusedLocationHardwareSecure.java b/services/core/java/com/android/server/location/FusedLocationHardwareSecure.java
similarity index 100%
rename from services/java/com/android/server/location/FusedLocationHardwareSecure.java
rename to services/core/java/com/android/server/location/FusedLocationHardwareSecure.java
diff --git a/services/java/com/android/server/location/FusedProxy.java b/services/core/java/com/android/server/location/FusedProxy.java
similarity index 100%
rename from services/java/com/android/server/location/FusedProxy.java
rename to services/core/java/com/android/server/location/FusedProxy.java
diff --git a/services/java/com/android/server/location/GeocoderProxy.java b/services/core/java/com/android/server/location/GeocoderProxy.java
similarity index 100%
rename from services/java/com/android/server/location/GeocoderProxy.java
rename to services/core/java/com/android/server/location/GeocoderProxy.java
diff --git a/services/java/com/android/server/location/GeofenceManager.java b/services/core/java/com/android/server/location/GeofenceManager.java
similarity index 100%
rename from services/java/com/android/server/location/GeofenceManager.java
rename to services/core/java/com/android/server/location/GeofenceManager.java
diff --git a/services/java/com/android/server/location/GeofenceProxy.java b/services/core/java/com/android/server/location/GeofenceProxy.java
similarity index 100%
rename from services/java/com/android/server/location/GeofenceProxy.java
rename to services/core/java/com/android/server/location/GeofenceProxy.java
diff --git a/services/java/com/android/server/location/GeofenceState.java b/services/core/java/com/android/server/location/GeofenceState.java
similarity index 100%
rename from services/java/com/android/server/location/GeofenceState.java
rename to services/core/java/com/android/server/location/GeofenceState.java
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
similarity index 100%
rename from services/java/com/android/server/location/GpsLocationProvider.java
rename to services/core/java/com/android/server/location/GpsLocationProvider.java
diff --git a/services/java/com/android/server/location/GpsXtraDownloader.java b/services/core/java/com/android/server/location/GpsXtraDownloader.java
similarity index 100%
rename from services/java/com/android/server/location/GpsXtraDownloader.java
rename to services/core/java/com/android/server/location/GpsXtraDownloader.java
diff --git a/services/java/com/android/server/location/LocationBasedCountryDetector.java b/services/core/java/com/android/server/location/LocationBasedCountryDetector.java
similarity index 100%
rename from services/java/com/android/server/location/LocationBasedCountryDetector.java
rename to services/core/java/com/android/server/location/LocationBasedCountryDetector.java
diff --git a/services/java/com/android/server/location/LocationBlacklist.java b/services/core/java/com/android/server/location/LocationBlacklist.java
similarity index 100%
rename from services/java/com/android/server/location/LocationBlacklist.java
rename to services/core/java/com/android/server/location/LocationBlacklist.java
diff --git a/services/java/com/android/server/location/LocationFudger.java b/services/core/java/com/android/server/location/LocationFudger.java
similarity index 100%
rename from services/java/com/android/server/location/LocationFudger.java
rename to services/core/java/com/android/server/location/LocationFudger.java
diff --git a/services/java/com/android/server/location/LocationProviderInterface.java b/services/core/java/com/android/server/location/LocationProviderInterface.java
similarity index 100%
rename from services/java/com/android/server/location/LocationProviderInterface.java
rename to services/core/java/com/android/server/location/LocationProviderInterface.java
diff --git a/services/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java
similarity index 100%
rename from services/java/com/android/server/location/LocationProviderProxy.java
rename to services/core/java/com/android/server/location/LocationProviderProxy.java
diff --git a/services/java/com/android/server/location/MockProvider.java b/services/core/java/com/android/server/location/MockProvider.java
similarity index 100%
rename from services/java/com/android/server/location/MockProvider.java
rename to services/core/java/com/android/server/location/MockProvider.java
diff --git a/services/java/com/android/server/location/PassiveProvider.java b/services/core/java/com/android/server/location/PassiveProvider.java
similarity index 100%
rename from services/java/com/android/server/location/PassiveProvider.java
rename to services/core/java/com/android/server/location/PassiveProvider.java
diff --git a/services/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
similarity index 100%
rename from services/java/com/android/server/media/MediaRouterService.java
rename to services/core/java/com/android/server/media/MediaRouterService.java
diff --git a/services/java/com/android/server/media/RemoteDisplayProviderProxy.java b/services/core/java/com/android/server/media/RemoteDisplayProviderProxy.java
similarity index 100%
rename from services/java/com/android/server/media/RemoteDisplayProviderProxy.java
rename to services/core/java/com/android/server/media/RemoteDisplayProviderProxy.java
diff --git a/services/java/com/android/server/media/RemoteDisplayProviderWatcher.java b/services/core/java/com/android/server/media/RemoteDisplayProviderWatcher.java
similarity index 100%
rename from services/java/com/android/server/media/RemoteDisplayProviderWatcher.java
rename to services/core/java/com/android/server/media/RemoteDisplayProviderWatcher.java
diff --git a/services/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
similarity index 100%
rename from services/java/com/android/server/net/LockdownVpnTracker.java
rename to services/core/java/com/android/server/net/LockdownVpnTracker.java
diff --git a/services/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java
similarity index 100%
rename from services/java/com/android/server/net/NetworkIdentitySet.java
rename to services/core/java/com/android/server/net/NetworkIdentitySet.java
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
similarity index 100%
rename from services/java/com/android/server/net/NetworkPolicyManagerService.java
rename to services/core/java/com/android/server/net/NetworkPolicyManagerService.java
diff --git a/services/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
similarity index 100%
rename from services/java/com/android/server/net/NetworkStatsCollection.java
rename to services/core/java/com/android/server/net/NetworkStatsCollection.java
diff --git a/services/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
similarity index 100%
rename from services/java/com/android/server/net/NetworkStatsRecorder.java
rename to services/core/java/com/android/server/net/NetworkStatsRecorder.java
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
similarity index 100%
rename from services/java/com/android/server/net/NetworkStatsService.java
rename to services/core/java/com/android/server/net/NetworkStatsService.java
diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java
new file mode 100644
index 0000000..df2aaca
--- /dev/null
+++ b/services/core/java/com/android/server/notification/NotificationDelegate.java
@@ -0,0 +1,27 @@
+/**
+ * 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.notification;
+
+public interface NotificationDelegate {
+    void onSetDisabled(int status);
+    void onClearAll();
+    void onNotificationClick(String pkg, String tag, int id);
+    void onNotificationClear(String pkg, String tag, int id);
+    void onNotificationError(String pkg, String tag, int id,
+            int uid, int initialPid, String message);
+    void onPanelRevealed();
+}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerInternal.java b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
new file mode 100644
index 0000000..92ffdcc
--- /dev/null
+++ b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
@@ -0,0 +1,8 @@
+package com.android.server.notification;
+
+import android.app.Notification;
+
+public interface NotificationManagerInternal {
+    void enqueueNotification(String pkg, String basePkg, int callingUid, int callingPid,
+            String tag, int id, Notification notification, int[] idReceived, int userId);
+}
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
similarity index 78%
rename from services/java/com/android/server/NotificationManagerService.java
rename to services/core/java/com/android/server/notification/NotificationManagerService.java
index 0438675..db4cf31d 100644
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.notification;
 
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.END_TAG;
@@ -47,7 +47,6 @@
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
 import android.media.AudioManager;
-import android.media.IAudioService;
 import android.media.IRingtonePlayer;
 import android.net.Uri;
 import android.os.Binder;
@@ -56,9 +55,7 @@
 import android.os.Message;
 import android.os.Process;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.UserHandle;
-import android.os.UserManager;
 import android.os.Vibrator;
 import android.provider.Settings;
 import android.service.notification.INotificationListener;
@@ -78,6 +75,12 @@
 import com.android.internal.R;
 
 import com.android.internal.notification.NotificationScorer;
+import com.android.server.EventLogTags;
+import com.android.server.statusbar.StatusBarManagerInternal;
+import com.android.server.SystemService;
+import com.android.server.lights.Light;
+import com.android.server.lights.LightsManager;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -99,66 +102,61 @@
 
 import libcore.io.IoUtils;
 
-
 /** {@hide} */
-public class NotificationManagerService extends INotificationManager.Stub
-{
-    private static final String TAG = "NotificationService";
-    private static final boolean DBG = false;
+public class NotificationManagerService extends SystemService {
+    static final String TAG = "NotificationService";
+    static final boolean DBG = false;
 
-    private static final int MAX_PACKAGE_NOTIFICATIONS = 50;
+    static final int MAX_PACKAGE_NOTIFICATIONS = 50;
 
     // message codes
-    private static final int MESSAGE_TIMEOUT = 2;
+    static final int MESSAGE_TIMEOUT = 2;
 
-    private static final int LONG_DELAY = 3500; // 3.5 seconds
-    private static final int SHORT_DELAY = 2000; // 2 seconds
+    static final int LONG_DELAY = 3500; // 3.5 seconds
+    static final int SHORT_DELAY = 2000; // 2 seconds
 
-    private static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
-    private static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
+    static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
+    static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
 
-    private static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
-    private static final boolean SCORE_ONGOING_HIGHER = false;
+    static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
+    static final boolean SCORE_ONGOING_HIGHER = false;
 
-    private static final int JUNK_SCORE = -1000;
-    private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10;
-    private static final int SCORE_DISPLAY_THRESHOLD = Notification.PRIORITY_MIN * NOTIFICATION_PRIORITY_MULTIPLIER;
+    static final int JUNK_SCORE = -1000;
+    static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10;
+    static final int SCORE_DISPLAY_THRESHOLD = Notification.PRIORITY_MIN * NOTIFICATION_PRIORITY_MULTIPLIER;
 
     // Notifications with scores below this will not interrupt the user, either via LED or
     // sound or vibration
-    private static final int SCORE_INTERRUPTION_THRESHOLD =
+    static final int SCORE_INTERRUPTION_THRESHOLD =
             Notification.PRIORITY_LOW * NOTIFICATION_PRIORITY_MULTIPLIER;
 
-    private static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true;
-    private static final boolean ENABLE_BLOCKED_TOASTS = true;
+    static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true;
+    static final boolean ENABLE_BLOCKED_TOASTS = true;
 
-    private static final String ENABLED_NOTIFICATION_LISTENERS_SEPARATOR = ":";
+    static final String ENABLED_NOTIFICATION_LISTENERS_SEPARATOR = ":";
 
-    final Context mContext;
-    final IActivityManager mAm;
-    final UserManager mUserManager;
+    private IActivityManager mAm;
+    AudioManager mAudioManager;
+    StatusBarManagerInternal mStatusBar;
+    Vibrator mVibrator;
+
     final IBinder mForegroundToken = new Binder();
-
     private WorkerHandler mHandler;
-    private StatusBarManagerService mStatusBar;
-    private LightsService.Light mNotificationLight;
-    private LightsService.Light mAttentionLight;
 
+    private Light mNotificationLight;
+    Light mAttentionLight;
     private int mDefaultNotificationColor;
     private int mDefaultNotificationLedOn;
+
     private int mDefaultNotificationLedOff;
-
     private long[] mDefaultVibrationPattern;
+
     private long[] mFallbackVibrationPattern;
+    boolean mSystemReady;
 
-    private boolean mSystemReady;
-    private int mDisabledNotifications;
-
-    private NotificationRecord mSoundNotification;
-    private NotificationRecord mVibrateNotification;
-
-    private IAudioService mAudioService;
-    private Vibrator mVibrator;
+    int mDisabledNotifications;
+    NotificationRecord mSoundNotification;
+    NotificationRecord mVibrateNotification;
 
     // for enabling and disabling notification pulse behavior
     private boolean mScreenOn = true;
@@ -166,15 +164,15 @@
     private boolean mNotificationPulseEnabled;
 
     // used as a mutex for access to all active notifications & listeners
-    private final ArrayList<NotificationRecord> mNotificationList =
+    final ArrayList<NotificationRecord> mNotificationList =
             new ArrayList<NotificationRecord>();
 
-    private ArrayList<ToastRecord> mToastQueue;
+    final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();
 
-    private ArrayList<NotificationRecord> mLights = new ArrayList<NotificationRecord>();
-    private NotificationRecord mLedNotification;
+    ArrayList<NotificationRecord> mLights = new ArrayList<NotificationRecord>();
+    NotificationRecord mLedNotification;
 
-    private final AppOpsManager mAppOps;
+    private AppOpsManager mAppOps;
 
     // contains connections to all connected listeners, including app services
     // and system listeners
@@ -202,9 +200,9 @@
     private static final String TAG_PACKAGE = "package";
     private static final String ATTR_NAME = "name";
 
-    private final ArrayList<NotificationScorer> mScorers = new ArrayList<NotificationScorer>();
+    final ArrayList<NotificationScorer> mScorers = new ArrayList<NotificationScorer>();
 
-    private class NotificationListenerInfo implements DeathRecipient {
+    private class NotificationListenerInfo implements IBinder.DeathRecipient {
         INotificationListener listener;
         ComponentName component;
         int userid;
@@ -262,7 +260,7 @@
         public void binderDied() {
             if (connection == null) {
                 // This is not a service; it won't be recreated. We can give up this connection.
-                unregisterListener(this.listener, this.userid);
+                unregisterListenerImpl(this.listener, this.userid);
             }
         }
 
@@ -400,12 +398,14 @@
                         tag = parser.getName();
                         if (type == START_TAG) {
                             if (TAG_BODY.equals(tag)) {
-                                version = Integer.parseInt(parser.getAttributeValue(null, ATTR_VERSION));
+                                version = Integer.parseInt(
+                                        parser.getAttributeValue(null, ATTR_VERSION));
                             } else if (TAG_BLOCKED_PKGS.equals(tag)) {
                                 while ((type = parser.next()) != END_DOCUMENT) {
                                     tag = parser.getName();
                                     if (TAG_PACKAGE.equals(tag)) {
-                                        mBlockedPackages.add(parser.getAttributeValue(null, ATTR_NAME));
+                                        mBlockedPackages.add(
+                                                parser.getAttributeValue(null, ATTR_NAME));
                                     } else if (TAG_BLOCKED_PKGS.equals(tag) && type == END_TAG) {
                                         break;
                                     }
@@ -428,15 +428,6 @@
         }
     }
 
-    /**
-     * Use this when you just want to know if notifications are OK for this package.
-     */
-    public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
-        checkCallerIsSystem();
-        return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
-                == AppOpsManager.MODE_ALLOWED);
-    }
-
     /** Use this when you actually want to post a notification or toast.
      *
      * Unchecked. Not exposed via Binder, but can be called in the course of enqueue*().
@@ -450,21 +441,6 @@
         return true;
     }
 
-    public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
-        checkCallerIsSystem();
-
-        Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
-
-        mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
-                enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
-
-        // Now, cancel any outstanding notifications that are part of a just-disabled app
-        if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
-            cancelAllNotificationsInt(pkg, 0, 0, true, UserHandle.getUserId(uid));
-        }
-    }
-
-
     private static String idDebugString(Context baseContext, String packageName, int id) {
         Context c = null;
 
@@ -490,57 +466,6 @@
         }
     }
 
-    /**
-     * System-only API for getting a list of current (i.e. not cleared) notifications.
-     *
-     * Requires ACCESS_NOTIFICATIONS which is signature|system.
-     */
-    @Override
-    public StatusBarNotification[] getActiveNotifications(String callingPkg) {
-        // enforce() will ensure the calling uid has the correct permission
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS,
-                "NotificationManagerService.getActiveNotifications");
-
-        StatusBarNotification[] tmp = null;
-        int uid = Binder.getCallingUid();
-
-        // noteOp will check to make sure the callingPkg matches the uid
-        if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
-                == AppOpsManager.MODE_ALLOWED) {
-            synchronized (mNotificationList) {
-                tmp = new StatusBarNotification[mNotificationList.size()];
-                final int N = mNotificationList.size();
-                for (int i=0; i<N; i++) {
-                    tmp[i] = mNotificationList.get(i).sbn;
-                }
-            }
-        }
-        return tmp;
-    }
-
-    /**
-     * System-only API for getting a list of recent (cleared, no longer shown) notifications.
-     *
-     * Requires ACCESS_NOTIFICATIONS which is signature|system.
-     */
-    @Override
-    public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
-        // enforce() will ensure the calling uid has the correct permission
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS,
-                "NotificationManagerService.getHistoricalNotifications");
-
-        StatusBarNotification[] tmp = null;
-        int uid = Binder.getCallingUid();
-
-        // noteOp will check to make sure the callingPkg matches the uid
-        if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
-                == AppOpsManager.MODE_ALLOWED) {
-            synchronized (mArchive) {
-                tmp = mArchive.getArray(count);
-            }
-        }
-        return tmp;
-    }
 
     /**
      * Remove notification access for any services that no longer exist.
@@ -548,12 +473,12 @@
     void disableNonexistentListeners() {
         int currentUser = ActivityManager.getCurrentUser();
         String flatIn = Settings.Secure.getStringForUser(
-                mContext.getContentResolver(),
+                getContext().getContentResolver(),
                 Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
                 currentUser);
         if (!TextUtils.isEmpty(flatIn)) {
             if (DBG) Slog.v(TAG, "flat before: " + flatIn);
-            PackageManager pm = mContext.getPackageManager();
+            PackageManager pm = getContext().getPackageManager();
             List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
                     new Intent(NotificationListenerService.SERVICE_INTERFACE),
                     PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
@@ -589,7 +514,7 @@
             }
             if (DBG) Slog.v(TAG, "flat after: " + flatOut);
             if (!flatIn.equals(flatOut)) {
-                Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                Settings.Secure.putStringForUser(getContext().getContentResolver(),
                         Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
                         flatOut, currentUser);
             }
@@ -603,7 +528,7 @@
     void rebindListenerServices() {
         final int currentUser = ActivityManager.getCurrentUser();
         String flat = Settings.Secure.getStringForUser(
-                mContext.getContentResolver(),
+                getContext().getContentResolver(),
                 Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
                 currentUser);
 
@@ -652,28 +577,6 @@
         }
     }
 
-    /**
-     * Register a listener binder directly with the notification manager.
-     *
-     * Only works with system callers. Apps should extend
-     * {@link android.service.notification.NotificationListenerService}.
-     */
-    @Override
-    public void registerListener(final INotificationListener listener,
-            final ComponentName component, final int userid) {
-        checkCallerIsSystem();
-
-        synchronized (mNotificationList) {
-            try {
-                NotificationListenerInfo info
-                        = new NotificationListenerInfo(listener, component, userid, true);
-                listener.asBinder().linkToDeath(info, 0);
-                mListeners.add(info);
-            } catch (RemoteException e) {
-                // already dead
-            }
-        }
-    }
 
     /**
      * Version of registerListener that takes the name of a
@@ -703,7 +606,7 @@
                     if (DBG) Slog.v(TAG, "    disconnecting old listener: " + info.listener);
                     mListeners.remove(i);
                     if (info.connection != null) {
-                        mContext.unbindService(info.connection);
+                        getContext().unbindService(info.connection);
                     }
                 }
             }
@@ -713,21 +616,25 @@
 
             intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
                     R.string.notification_listener_binding_label);
-            intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
-                    mContext, 0, new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS), 0));
+
+            final PendingIntent pendingIntent = PendingIntent.getActivity(
+                    getContext(), 0, new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS), 0);
+            intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent);
 
             try {
                 if (DBG) Slog.v(TAG, "binding: " + intent);
-                if (!mContext.bindServiceAsUser(intent,
+                if (!getContext().bindServiceAsUser(intent,
                         new ServiceConnection() {
                             INotificationListener mListener;
+
                             @Override
                             public void onServiceConnected(ComponentName name, IBinder service) {
                                 synchronized (mNotificationList) {
                                     mServicesBinding.remove(servicesBindingTag);
                                     try {
                                         mListener = INotificationListener.Stub.asInterface(service);
-                                        NotificationListenerInfo info = new NotificationListenerInfo(
+                                        NotificationListenerInfo info
+                                                = new NotificationListenerInfo(
                                                 mListener, name, userid, this);
                                         service.linkToDeath(info, 0);
                                         mListeners.add(info);
@@ -756,28 +663,6 @@
         }
     }
 
-    /**
-     * Remove a listener binder directly
-     */
-    @Override
-    public void unregisterListener(INotificationListener listener, int userid) {
-        // no need to check permissions; if your listener binder is in the list,
-        // that's proof that you had permission to add it in the first place
-
-        synchronized (mNotificationList) {
-            final int N = mListeners.size();
-            for (int i=N-1; i>=0; i--) {
-                final NotificationListenerInfo info = mListeners.get(i);
-                if (info.listener.asBinder() == listener.asBinder()
-                        && info.userid == userid) {
-                    mListeners.remove(i);
-                    if (info.connection != null) {
-                        mContext.unbindService(info.connection);
-                    }
-                }
-            }
-        }
-    }
 
     /**
      * Remove a listener service for the given user by ComponentName
@@ -794,7 +679,7 @@
                     mListeners.remove(i);
                     if (info.connection != null) {
                         try {
-                            mContext.unbindService(info.connection);
+                            getContext().unbindService(info.connection);
                         } catch (IllegalArgumentException ex) {
                             // something happened to the service: we think we have a connection
                             // but it's bogus.
@@ -809,7 +694,7 @@
     /**
      * asynchronously notify all listeners about a new notification
      */
-    private void notifyPostedLocked(NotificationRecord n) {
+    void notifyPostedLocked(NotificationRecord n) {
         // make a copy in case changes are made to the underlying Notification object
         final StatusBarNotification sbn = n.sbn.clone();
         for (final NotificationListenerInfo info : mListeners) {
@@ -824,7 +709,7 @@
     /**
      * asynchronously notify all listeners about a removed notification
      */
-    private void notifyRemovedLocked(NotificationRecord n) {
+    void notifyRemovedLocked(NotificationRecord n) {
         // make a copy in case changes are made to the underlying Notification object
         // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the notification
         final StatusBarNotification sbn_light = n.sbn.cloneLight();
@@ -850,66 +735,7 @@
         throw new SecurityException("Disallowed call from unknown listener: " + listener);
     }
 
-    /**
-     * Allow an INotificationListener to simulate a "clear all" operation.
-     *
-     * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
-     *
-     * @param token The binder for the listener, to check that the caller is allowed
-     */
-    public void cancelAllNotificationsFromListener(INotificationListener token) {
-        NotificationListenerInfo info = checkListenerToken(token);
-        long identity = Binder.clearCallingIdentity();
-        try {
-            cancelAll(info.userid);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
 
-    /**
-     * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
-     *
-     * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
-     *
-     * @param token The binder for the listener, to check that the caller is allowed
-     */
-    public void cancelNotificationFromListener(INotificationListener token, String pkg, String tag, int id) {
-        NotificationListenerInfo info = checkListenerToken(token);
-        long identity = Binder.clearCallingIdentity();
-        try {
-            cancelNotification(pkg, tag, id, 0,
-                    Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
-                    true,
-                    info.userid);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    /**
-     * Allow an INotificationListener to request the list of outstanding notifications seen by
-     * the current user. Useful when starting up, after which point the listener callbacks should
-     * be used.
-     *
-     * @param token The binder for the listener, to check that the caller is allowed
-     */
-    public StatusBarNotification[] getActiveNotificationsFromListener(INotificationListener token) {
-        NotificationListenerInfo info = checkListenerToken(token);
-
-        StatusBarNotification[] result = new StatusBarNotification[0];
-        ArrayList<StatusBarNotification> list = new ArrayList<StatusBarNotification>();
-        synchronized (mNotificationList) {
-            final int N = mNotificationList.size();
-            for (int i=0; i<N; i++) {
-                StatusBarNotification sbn = mNotificationList.get(i).sbn;
-                if (info.enabledAndUserMatches(sbn)) {
-                    list.add(sbn);
-                }
-            }
-        }
-        return list.toArray(result);
-    }
 
     // -- end of listener APIs --
 
@@ -992,8 +818,8 @@
             return String.format(
                     "NotificationRecord(0x%08x: pkg=%s user=%s id=%d tag=%s score=%d: %s)",
                     System.identityHashCode(this),
-                    this.sbn.getPackageName(), this.sbn.getUser(), this.sbn.getId(), this.sbn.getTag(),
-                    this.sbn.getScore(), this.sbn.getNotification());
+                    this.sbn.getPackageName(), this.sbn.getUser(), this.sbn.getId(),
+                    this.sbn.getTag(), this.sbn.getScore(), this.sbn.getNotification());
         }
     }
 
@@ -1031,9 +857,9 @@
         }
     }
 
-    private StatusBarManagerService.NotificationCallbacks mNotificationCallbacks
-            = new StatusBarManagerService.NotificationCallbacks() {
+    private final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
 
+        @Override
         public void onSetDisabled(int status) {
             synchronized (mNotificationList) {
                 mDisabledNotifications = status;
@@ -1041,7 +867,7 @@
                     // cancel whatever's going on
                     long identity = Binder.clearCallingIdentity();
                     try {
-                        final IRingtonePlayer player = mAudioService.getRingtonePlayer();
+                        final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
                         if (player != null) {
                             player.stopAsync();
                         }
@@ -1060,12 +886,14 @@
             }
         }
 
+        @Override
         public void onClearAll() {
             // XXX to be totally correct, the caller should tell us which user
             // this is for.
             cancelAll(ActivityManager.getCurrentUser());
         }
 
+        @Override
         public void onNotificationClick(String pkg, String tag, int id) {
             // XXX to be totally correct, the caller should tell us which user
             // this is for.
@@ -1074,6 +902,7 @@
                     ActivityManager.getCurrentUser());
         }
 
+        @Override
         public void onNotificationClear(String pkg, String tag, int id) {
             // XXX to be totally correct, the caller should tell us which user
             // this is for.
@@ -1082,6 +911,7 @@
                 true, ActivityManager.getCurrentUser());
         }
 
+        @Override
         public void onPanelRevealed() {
             synchronized (mNotificationList) {
                 // sound
@@ -1089,7 +919,7 @@
 
                 long identity = Binder.clearCallingIdentity();
                 try {
-                    final IRingtonePlayer player = mAudioService.getRingtonePlayer();
+                    final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
                     if (player != null) {
                         player.stopAsync();
                     }
@@ -1114,6 +944,7 @@
             }
         }
 
+        @Override
         public void onNotificationError(String pkg, String tag, int id,
                 int uid, int initialPid, String message) {
             Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
@@ -1168,7 +999,7 @@
                     if (packageChanged) {
                         // We cancel notifications for packages which have just been disabled
                         try {
-                            final int enabled = mContext.getPackageManager()
+                            final int enabled = getContext().getPackageManager()
                                     .getApplicationEnabledSetting(pkgName);
                             if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
                                     || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
@@ -1244,7 +1075,7 @@
         }
 
         void observe() {
-            ContentResolver resolver = mContext.getContentResolver();
+            ContentResolver resolver = getContext().getContentResolver();
             resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
                     false, this, UserHandle.USER_ALL);
             resolver.registerContentObserver(ENABLED_NOTIFICATION_LISTENERS_URI,
@@ -1257,7 +1088,7 @@
         }
 
         public void update(Uri uri) {
-            ContentResolver resolver = mContext.getContentResolver();
+            ContentResolver resolver = getContext().getContentResolver();
             if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
                 boolean pulseEnabled = Settings.System.getInt(resolver,
                             Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
@@ -1287,28 +1118,24 @@
         return out;
     }
 
-    NotificationManagerService(Context context, StatusBarManagerService statusBar,
-            LightsService lights)
-    {
-        super();
-        mContext = context;
-        mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
+    @Override
+    public void onStart() {
         mAm = ActivityManagerNative.getDefault();
-        mUserManager = (UserManager)context.getSystemService(Context.USER_SERVICE);
-        mToastQueue = new ArrayList<ToastRecord>();
-        mHandler = new WorkerHandler();
+        mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
+        mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
 
-        mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
+        mHandler = new WorkerHandler();
 
         importOldBlockDb();
 
-        mStatusBar = statusBar;
-        statusBar.setNotificationCallbacks(mNotificationCallbacks);
+        mStatusBar = getLocalService(StatusBarManagerInternal.class);
+        mStatusBar.setNotificationDelegate(mNotificationDelegate);
 
-        mNotificationLight = lights.getLight(LightsService.LIGHT_ID_NOTIFICATIONS);
-        mAttentionLight = lights.getLight(LightsService.LIGHT_ID_ATTENTION);
+        final LightsManager lights = getLocalService(LightsManager.class);
+        mNotificationLight = lights.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
+        mAttentionLight = lights.getLight(LightsManager.LIGHT_ID_ATTENTION);
 
-        Resources resources = mContext.getResources();
+        Resources resources = getContext().getResources();
         mDefaultNotificationColor = resources.getColor(
                 R.color.config_defaultNotificationColor);
         mDefaultNotificationLedOn = resources.getInteger(
@@ -1330,7 +1157,7 @@
         // After that, including subsequent boots, init with notifications turned on.
         // This works on the first boot because the setup wizard will toggle this
         // flag at least once and we'll go back to 0 after that.
-        if (0 == Settings.Global.getInt(mContext.getContentResolver(),
+        if (0 == Settings.Global.getInt(getContext().getContentResolver(),
                     Settings.Global.DEVICE_PROVISIONED, 0)) {
             mDisabledNotifications = StatusBarManager.DISABLE_NOTIFICATION_ALERTS;
         }
@@ -1343,7 +1170,7 @@
         filter.addAction(Intent.ACTION_USER_PRESENT);
         filter.addAction(Intent.ACTION_USER_STOPPED);
         filter.addAction(Intent.ACTION_USER_SWITCHED);
-        mContext.registerReceiver(mIntentReceiver, filter);
+        getContext().registerReceiver(mIntentReceiver, filter);
         IntentFilter pkgFilter = new IntentFilter();
         pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
         pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
@@ -1351,9 +1178,9 @@
         pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
         pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
         pkgFilter.addDataScheme("package");
-        mContext.registerReceiver(mIntentReceiver, pkgFilter);
+        getContext().registerReceiver(mIntentReceiver, pkgFilter);
         IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
-        mContext.registerReceiver(mIntentReceiver, sdFilter);
+        getContext().registerReceiver(mIntentReceiver, sdFilter);
 
         mSettingsObserver = new SettingsObserver(mHandler);
         mSettingsObserver.observe();
@@ -1363,9 +1190,9 @@
                 R.array.config_notificationScorers);
         for (String scorerName : notificationScorerNames) {
             try {
-                Class<?> scorerClass = mContext.getClassLoader().loadClass(scorerName);
+                Class<?> scorerClass = getContext().getClassLoader().loadClass(scorerName);
                 NotificationScorer scorer = (NotificationScorer) scorerClass.newInstance();
-                scorer.initialize(mContext);
+                scorer.initialize(getContext());
                 mScorers.add(scorer);
             } catch (ClassNotFoundException e) {
                 Slog.w(TAG, "Couldn't find scorer " + scorerName + ".", e);
@@ -1375,6 +1202,9 @@
                 Slog.w(TAG, "Problem accessing scorer " + scorerName + ".", e);
             }
         }
+
+        publishBinderService(Context.NOTIFICATION_SERVICE, mService);
+        publishLocalService(NotificationManagerInternal.class, mInternalService);
     }
 
     /**
@@ -1383,12 +1213,12 @@
     private void importOldBlockDb() {
         loadBlockDb();
 
-        PackageManager pm = mContext.getPackageManager();
+        PackageManager pm = getContext().getPackageManager();
         for (String pkg : mBlockedPackages) {
             PackageInfo info = null;
             try {
                 info = pm.getPackageInfo(pkg, 0);
-                setNotificationsEnabledForPackage(pkg, info.applicationInfo.uid, false);
+                setNotificationsEnabledForPackageImpl(pkg, info.applicationInfo.uid, false);
             } catch (NameNotFoundException e) {
                 // forget you
             }
@@ -1399,244 +1229,421 @@
         }
     }
 
-    void systemReady() {
-        mAudioService = IAudioService.Stub.asInterface(
-                ServiceManager.getService(Context.AUDIO_SERVICE));
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+            // no beeping until we're basically done booting
+            mSystemReady = true;
 
-        // no beeping until we're basically done booting
-        mSystemReady = true;
+            // Grab our optional AudioService
+            mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
 
-        // make sure our listener services are properly bound
-        rebindListenerServices();
-    }
-
-    // Toasts
-    // ============================================================================
-    public void enqueueToast(String pkg, ITransientNotification callback, int duration)
-    {
-        if (DBG) Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback + " duration=" + duration);
-
-        if (pkg == null || callback == null) {
-            Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
-            return ;
-        }
-
-        final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg));
-
-        if (ENABLE_BLOCKED_TOASTS && !noteNotificationOp(pkg, Binder.getCallingUid())) {
-            if (!isSystemToast) {
-                Slog.e(TAG, "Suppressing toast from package " + pkg + " by user request.");
-                return;
-            }
-        }
-
-        synchronized (mToastQueue) {
-            int callingPid = Binder.getCallingPid();
-            long callingId = Binder.clearCallingIdentity();
-            try {
-                ToastRecord record;
-                int index = indexOfToastLocked(pkg, callback);
-                // If it's already in the queue, we update it in place, we don't
-                // move it to the end of the queue.
-                if (index >= 0) {
-                    record = mToastQueue.get(index);
-                    record.update(duration);
-                } else {
-                    // Limit the number of toasts that any given package except the android
-                    // package can enqueue.  Prevents DOS attacks and deals with leaks.
-                    if (!isSystemToast) {
-                        int count = 0;
-                        final int N = mToastQueue.size();
-                        for (int i=0; i<N; i++) {
-                             final ToastRecord r = mToastQueue.get(i);
-                             if (r.pkg.equals(pkg)) {
-                                 count++;
-                                 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
-                                     Slog.e(TAG, "Package has already posted " + count
-                                            + " toasts. Not showing more. Package=" + pkg);
-                                     return;
-                                 }
-                             }
-                        }
-                    }
-
-                    record = new ToastRecord(callingPid, pkg, callback, duration);
-                    mToastQueue.add(record);
-                    index = mToastQueue.size() - 1;
-                    keepProcessAliveLocked(callingPid);
-                }
-                // If it's at index 0, it's the current toast.  It doesn't matter if it's
-                // new or just been updated.  Call back and tell it to show itself.
-                // If the callback fails, this will remove it from the list, so don't
-                // assume that it's valid after this.
-                if (index == 0) {
-                    showNextToastLocked();
-                }
-            } finally {
-                Binder.restoreCallingIdentity(callingId);
-            }
+            // make sure our listener services are properly bound
+            rebindListenerServices();
         }
     }
 
-    public void cancelToast(String pkg, ITransientNotification callback) {
-        Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
+    void setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled) {
+        Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
 
-        if (pkg == null || callback == null) {
-            Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
-            return ;
-        }
+        mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
+                enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
 
-        synchronized (mToastQueue) {
-            long callingId = Binder.clearCallingIdentity();
-            try {
-                int index = indexOfToastLocked(pkg, callback);
-                if (index >= 0) {
-                    cancelToastLocked(index);
-                } else {
-                    Slog.w(TAG, "Toast already cancelled. pkg=" + pkg + " callback=" + callback);
-                }
-            } finally {
-                Binder.restoreCallingIdentity(callingId);
-            }
+        // Now, cancel any outstanding notifications that are part of a just-disabled app
+        if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
+            cancelAllNotificationsInt(pkg, 0, 0, true, UserHandle.getUserId(uid));
         }
     }
 
-    private void showNextToastLocked() {
-        ToastRecord record = mToastQueue.get(0);
-        while (record != null) {
-            if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
-            try {
-                record.callback.show();
-                scheduleTimeoutLocked(record);
-                return;
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Object died trying to show notification " + record.callback
-                        + " in package " + record.pkg);
-                // remove it from the list and let the process die
-                int index = mToastQueue.indexOf(record);
-                if (index >= 0) {
-                    mToastQueue.remove(index);
-                }
-                keepProcessAliveLocked(record.pid);
-                if (mToastQueue.size() > 0) {
-                    record = mToastQueue.get(0);
-                } else {
-                    record = null;
-                }
-            }
-        }
-    }
+    private final IBinder mService = new INotificationManager.Stub() {
+        // Toasts
+        // ============================================================================
 
-    private void cancelToastLocked(int index) {
-        ToastRecord record = mToastQueue.get(index);
-        try {
-            record.callback.hide();
-        } catch (RemoteException e) {
-            Slog.w(TAG, "Object died trying to hide notification " + record.callback
-                    + " in package " + record.pkg);
-            // don't worry about this, we're about to remove it from
-            // the list anyway
-        }
-        mToastQueue.remove(index);
-        keepProcessAliveLocked(record.pid);
-        if (mToastQueue.size() > 0) {
-            // Show the next one. If the callback fails, this will remove
-            // it from the list, so don't assume that the list hasn't changed
-            // after this point.
-            showNextToastLocked();
-        }
-    }
-
-    private void scheduleTimeoutLocked(ToastRecord r)
-    {
-        mHandler.removeCallbacksAndMessages(r);
-        Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
-        long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
-        mHandler.sendMessageDelayed(m, delay);
-    }
-
-    private void handleTimeout(ToastRecord record)
-    {
-        if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
-        synchronized (mToastQueue) {
-            int index = indexOfToastLocked(record.pkg, record.callback);
-            if (index >= 0) {
-                cancelToastLocked(index);
-            }
-        }
-    }
-
-    // lock on mToastQueue
-    private int indexOfToastLocked(String pkg, ITransientNotification callback)
-    {
-        IBinder cbak = callback.asBinder();
-        ArrayList<ToastRecord> list = mToastQueue;
-        int len = list.size();
-        for (int i=0; i<len; i++) {
-            ToastRecord r = list.get(i);
-            if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    // lock on mToastQueue
-    private void keepProcessAliveLocked(int pid)
-    {
-        int toastCount = 0; // toasts from this pid
-        ArrayList<ToastRecord> list = mToastQueue;
-        int N = list.size();
-        for (int i=0; i<N; i++) {
-            ToastRecord r = list.get(i);
-            if (r.pid == pid) {
-                toastCount++;
-            }
-        }
-        try {
-            mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
-        } catch (RemoteException e) {
-            // Shouldn't happen.
-        }
-    }
-
-    private final class WorkerHandler extends Handler
-    {
         @Override
-        public void handleMessage(Message msg)
+        public void enqueueToast(String pkg, ITransientNotification callback, int duration)
         {
-            switch (msg.what)
-            {
-                case MESSAGE_TIMEOUT:
-                    handleTimeout((ToastRecord)msg.obj);
-                    break;
+            if (DBG) {
+                Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
+                        + " duration=" + duration);
             }
+
+            if (pkg == null || callback == null) {
+                Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
+                return ;
+            }
+
+            final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg));
+
+            if (ENABLE_BLOCKED_TOASTS && !noteNotificationOp(pkg, Binder.getCallingUid())) {
+                if (!isSystemToast) {
+                    Slog.e(TAG, "Suppressing toast from package " + pkg + " by user request.");
+                    return;
+                }
+            }
+
+            synchronized (mToastQueue) {
+                int callingPid = Binder.getCallingPid();
+                long callingId = Binder.clearCallingIdentity();
+                try {
+                    ToastRecord record;
+                    int index = indexOfToastLocked(pkg, callback);
+                    // If it's already in the queue, we update it in place, we don't
+                    // move it to the end of the queue.
+                    if (index >= 0) {
+                        record = mToastQueue.get(index);
+                        record.update(duration);
+                    } else {
+                        // Limit the number of toasts that any given package except the android
+                        // package can enqueue.  Prevents DOS attacks and deals with leaks.
+                        if (!isSystemToast) {
+                            int count = 0;
+                            final int N = mToastQueue.size();
+                            for (int i=0; i<N; i++) {
+                                 final ToastRecord r = mToastQueue.get(i);
+                                 if (r.pkg.equals(pkg)) {
+                                     count++;
+                                     if (count >= MAX_PACKAGE_NOTIFICATIONS) {
+                                         Slog.e(TAG, "Package has already posted " + count
+                                                + " toasts. Not showing more. Package=" + pkg);
+                                         return;
+                                     }
+                                 }
+                            }
+                        }
+
+                        record = new ToastRecord(callingPid, pkg, callback, duration);
+                        mToastQueue.add(record);
+                        index = mToastQueue.size() - 1;
+                        keepProcessAliveLocked(callingPid);
+                    }
+                    // If it's at index 0, it's the current toast.  It doesn't matter if it's
+                    // new or just been updated.  Call back and tell it to show itself.
+                    // If the callback fails, this will remove it from the list, so don't
+                    // assume that it's valid after this.
+                    if (index == 0) {
+                        showNextToastLocked();
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(callingId);
+                }
+            }
+        }
+
+        @Override
+        public void cancelToast(String pkg, ITransientNotification callback) {
+            Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
+
+            if (pkg == null || callback == null) {
+                Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
+                return ;
+            }
+
+            synchronized (mToastQueue) {
+                long callingId = Binder.clearCallingIdentity();
+                try {
+                    int index = indexOfToastLocked(pkg, callback);
+                    if (index >= 0) {
+                        cancelToastLocked(index);
+                    } else {
+                        Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
+                                + " callback=" + callback);
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(callingId);
+                }
+            }
+        }
+
+        @Override
+        public void enqueueNotificationWithTag(String pkg, String basePkg, String tag, int id,
+                Notification notification, int[] idOut, int userId) throws RemoteException {
+            enqueueNotificationInternal(pkg, basePkg, Binder.getCallingUid(),
+                    Binder.getCallingPid(), tag, id, notification, idOut, userId);
+        }
+
+        @Override
+        public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
+            checkCallerIsSystemOrSameApp(pkg);
+            userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
+                    Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
+            // Don't allow client applications to cancel foreground service notis.
+            cancelNotification(pkg, tag, id, 0,
+                    Binder.getCallingUid() == Process.SYSTEM_UID
+                    ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false, userId);
+        }
+
+        @Override
+        public void cancelAllNotifications(String pkg, int userId) {
+            checkCallerIsSystemOrSameApp(pkg);
+
+            userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
+                    Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
+
+            // Calling from user space, don't allow the canceling of actively
+            // running foreground services.
+            cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId);
+        }
+
+        @Override
+        public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
+            checkCallerIsSystem();
+
+            setNotificationsEnabledForPackageImpl(pkg, uid, enabled);
+        }
+
+        /**
+         * Use this when you just want to know if notifications are OK for this package.
+         */
+        @Override
+        public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
+            checkCallerIsSystem();
+            return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
+                    == AppOpsManager.MODE_ALLOWED);
+        }
+
+        /**
+         * System-only API for getting a list of current (i.e. not cleared) notifications.
+         *
+         * Requires ACCESS_NOTIFICATIONS which is signature|system.
+         */
+        @Override
+        public StatusBarNotification[] getActiveNotifications(String callingPkg) {
+            // enforce() will ensure the calling uid has the correct permission
+            getContext().enforceCallingOrSelfPermission(
+                    android.Manifest.permission.ACCESS_NOTIFICATIONS,
+                    "NotificationManagerService.getActiveNotifications");
+
+            StatusBarNotification[] tmp = null;
+            int uid = Binder.getCallingUid();
+
+            // noteOp will check to make sure the callingPkg matches the uid
+            if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
+                    == AppOpsManager.MODE_ALLOWED) {
+                synchronized (mNotificationList) {
+                    tmp = new StatusBarNotification[mNotificationList.size()];
+                    final int N = mNotificationList.size();
+                    for (int i=0; i<N; i++) {
+                        tmp[i] = mNotificationList.get(i).sbn;
+                    }
+                }
+            }
+            return tmp;
+        }
+
+        /**
+         * System-only API for getting a list of recent (cleared, no longer shown) notifications.
+         *
+         * Requires ACCESS_NOTIFICATIONS which is signature|system.
+         */
+        @Override
+        public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
+            // enforce() will ensure the calling uid has the correct permission
+            getContext().enforceCallingOrSelfPermission(
+                    android.Manifest.permission.ACCESS_NOTIFICATIONS,
+                    "NotificationManagerService.getHistoricalNotifications");
+
+            StatusBarNotification[] tmp = null;
+            int uid = Binder.getCallingUid();
+
+            // noteOp will check to make sure the callingPkg matches the uid
+            if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
+                    == AppOpsManager.MODE_ALLOWED) {
+                synchronized (mArchive) {
+                    tmp = mArchive.getArray(count);
+                }
+            }
+            return tmp;
+        }
+
+        /**
+         * Register a listener binder directly with the notification manager.
+         *
+         * Only works with system callers. Apps should extend
+         * {@link android.service.notification.NotificationListenerService}.
+         */
+        @Override
+        public void registerListener(final INotificationListener listener,
+                final ComponentName component, final int userid) {
+            checkCallerIsSystem();
+            registerListenerImpl(listener, component, userid);
+        }
+
+        /**
+         * Remove a listener binder directly
+         */
+        @Override
+        public void unregisterListener(INotificationListener listener, int userid) {
+            // no need to check permissions; if your listener binder is in the list,
+            // that's proof that you had permission to add it in the first place
+            unregisterListenerImpl(listener, userid);
+        }
+
+        /**
+         * Allow an INotificationListener to simulate a "clear all" operation.
+         *
+         * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
+         *
+         * @param token The binder for the listener, to check that the caller is allowed
+         */
+        @Override
+        public void cancelAllNotificationsFromListener(INotificationListener token) {
+            NotificationListenerInfo info = checkListenerToken(token);
+            long identity = Binder.clearCallingIdentity();
+            try {
+                cancelAll(info.userid);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        /**
+         * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
+         *
+         * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
+         *
+         * @param token The binder for the listener, to check that the caller is allowed
+         */
+        @Override
+        public void cancelNotificationFromListener(INotificationListener token, String pkg,
+                String tag, int id) {
+            NotificationListenerInfo info = checkListenerToken(token);
+            long identity = Binder.clearCallingIdentity();
+            try {
+                cancelNotification(pkg, tag, id, 0,
+                        Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
+                        true,
+                        info.userid);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        /**
+         * Allow an INotificationListener to request the list of outstanding notifications seen by
+         * the current user. Useful when starting up, after which point the listener callbacks
+         * should be used.
+         *
+         * @param token The binder for the listener, to check that the caller is allowed
+         */
+        @Override
+        public StatusBarNotification[] getActiveNotificationsFromListener(
+                INotificationListener token) {
+            NotificationListenerInfo info = checkListenerToken(token);
+
+            StatusBarNotification[] result = new StatusBarNotification[0];
+            ArrayList<StatusBarNotification> list = new ArrayList<StatusBarNotification>();
+            synchronized (mNotificationList) {
+                final int N = mNotificationList.size();
+                for (int i=0; i<N; i++) {
+                    StatusBarNotification sbn = mNotificationList.get(i).sbn;
+                    if (info.enabledAndUserMatches(sbn)) {
+                        list.add(sbn);
+                    }
+                }
+            }
+            return list.toArray(result);
+        }
+
+        @Override
+        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                    != PackageManager.PERMISSION_GRANTED) {
+                pw.println("Permission Denial: can't dump NotificationManager from from pid="
+                        + Binder.getCallingPid()
+                        + ", uid=" + Binder.getCallingUid());
+                return;
+            }
+
+            dumpImpl(pw);
+        }
+    };
+
+    void dumpImpl(PrintWriter pw) {
+        pw.println("Current Notification Manager state:");
+
+        pw.println("  Listeners (" + mEnabledListenersForCurrentUser.size()
+                + ") enabled for current user:");
+        for (ComponentName cmpt : mEnabledListenersForCurrentUser) {
+            pw.println("    " + cmpt);
+        }
+
+        pw.println("  Live listeners (" + mListeners.size() + "):");
+        for (NotificationListenerInfo info : mListeners) {
+            pw.println("    " + info.component
+                    + " (user " + info.userid + "): " + info.listener
+                    + (info.isSystem?" SYSTEM":""));
+        }
+
+        int N;
+
+        synchronized (mToastQueue) {
+            N = mToastQueue.size();
+            if (N > 0) {
+                pw.println("  Toast Queue:");
+                for (int i=0; i<N; i++) {
+                    mToastQueue.get(i).dump(pw, "    ");
+                }
+                pw.println("  ");
+            }
+
+        }
+
+        synchronized (mNotificationList) {
+            N = mNotificationList.size();
+            if (N > 0) {
+                pw.println("  Notification List:");
+                for (int i=0; i<N; i++) {
+                    mNotificationList.get(i).dump(pw, "    ", getContext());
+                }
+                pw.println("  ");
+            }
+
+            N = mLights.size();
+            if (N > 0) {
+                pw.println("  Lights List:");
+                for (int i=0; i<N; i++) {
+                    pw.println("    " + mLights.get(i));
+                }
+                pw.println("  ");
+            }
+
+            pw.println("  mSoundNotification=" + mSoundNotification);
+            pw.println("  mVibrateNotification=" + mVibrateNotification);
+            pw.println("  mDisabledNotifications=0x"
+                    + Integer.toHexString(mDisabledNotifications));
+            pw.println("  mSystemReady=" + mSystemReady);
+            pw.println("  mArchive=" + mArchive.toString());
+            Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
+            int i=0;
+            while (iter.hasNext()) {
+                pw.println("    " + iter.next());
+                if (++i >= 5) {
+                    if (iter.hasNext()) pw.println("    ...");
+                    break;
+                }
+            }
+
         }
     }
 
+    /**
+     * The private API only accessible to the system process.
+     */
+    private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
+        @Override
+        public void enqueueNotification(String pkg, String basePkg, int callingUid, int callingPid,
+                String tag, int id, Notification notification, int[] idReceived, int userId) {
+            enqueueNotificationInternal(pkg, basePkg, callingUid, callingPid, tag, id, notification,
+                    idReceived, userId);
+        }
+    };
 
-    // Notifications
-    // ============================================================================
-    public void enqueueNotificationWithTag(String pkg, String basePkg, String tag, int id,
-            Notification notification, int[] idOut, int userId)
-    {
-        enqueueNotificationInternal(pkg, basePkg, Binder.getCallingUid(), Binder.getCallingPid(),
-                tag, id, notification, idOut, userId);
-    }
-    
-    private final static int clamp(int x, int low, int high) {
-        return (x < low) ? low : ((x > high) ? high : x);
-    }
-
-    // Not exposed via Binder; for system use only (otherwise malicious apps could spoof the
-    // uid/pid of another application)
-
-    public void enqueueNotificationInternal(final String pkg, String basePkg, final int callingUid,
+    void enqueueNotificationInternal(final String pkg, String basePkg, final int callingUid,
             final int callingPid, final String tag, final int id, final Notification notification,
-            int[] idOut, int incomingUserId)
-    {
+            int[] idOut, int incomingUserId) {
         if (DBG) {
-            Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id + " notification=" + notification);
+            Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
+                    + " notification=" + notification);
         }
         checkCallerIsSystemOrSameApp(pkg);
         final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg));
@@ -1787,23 +1794,21 @@
                     if (notification.icon != 0) {
                         if (old != null && old.statusBarKey != null) {
                             r.statusBarKey = old.statusBarKey;
-                            long identity = Binder.clearCallingIdentity();
+                            final long identity = Binder.clearCallingIdentity();
                             try {
                                 mStatusBar.updateNotification(r.statusBarKey, n);
-                            }
-                            finally {
+                            } finally {
                                 Binder.restoreCallingIdentity(identity);
                             }
                         } else {
-                            long identity = Binder.clearCallingIdentity();
+                            final long identity = Binder.clearCallingIdentity();
                             try {
                                 r.statusBarKey = mStatusBar.addNotification(n);
                                 if ((n.getNotification().flags & Notification.FLAG_SHOW_LIGHTS) != 0
                                         && canInterrupt) {
                                     mAttentionLight.pulse();
                                 }
-                            }
-                            finally {
+                            } finally {
                                 Binder.restoreCallingIdentity(identity);
                             }
                         }
@@ -1816,33 +1821,32 @@
                     } else {
                         Slog.e(TAG, "Not posting notification with icon==0: " + notification);
                         if (old != null && old.statusBarKey != null) {
-                            long identity = Binder.clearCallingIdentity();
+                            final long identity = Binder.clearCallingIdentity();
                             try {
                                 mStatusBar.removeNotification(old.statusBarKey);
-                            }
-                            finally {
+                            } finally {
                                 Binder.restoreCallingIdentity(identity);
                             }
 
                             notifyRemovedLocked(r);
                         }
                         // ATTENTION: in a future release we will bail out here
-                        // so that we do not play sounds, show lights, etc. for invalid notifications
+                        // so that we do not play sounds, show lights, etc. for invalid
+                        // notifications
                         Slog.e(TAG, "WARNING: In a future release this will crash the app: "
                                 + n.getPackageName());
                     }
 
                     // If we're not supposed to beep, vibrate, etc. then don't.
-                    if (((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0)
+                    if (((mDisabledNotifications
+                            & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0)
                             && (!(old != null
                                 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
                             && (r.getUserId() == UserHandle.USER_ALL ||
                                 (r.getUserId() == userId && r.getUserId() == currentUser))
                             && canInterrupt
-                            && mSystemReady) {
-
-                        final AudioManager audioManager = (AudioManager) mContext
-                        .getSystemService(Context.AUDIO_SERVICE);
+                            && mSystemReady
+                            && mAudioManager != null) {
 
                         // sound
 
@@ -1861,7 +1865,7 @@
                             soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
 
                             // check to see if the default notification sound is silent
-                            ContentResolver resolver = mContext.getContentResolver();
+                            ContentResolver resolver = getContext().getContentResolver();
                             hasValidSound = Settings.System.getString(resolver,
                                    Settings.System.NOTIFICATION_SOUND) != null;
                         } else if (notification.sound != null) {
@@ -1870,7 +1874,8 @@
                         }
 
                         if (hasValidSound) {
-                            boolean looping = (notification.flags & Notification.FLAG_INSISTENT) != 0;
+                            boolean looping =
+                                    (notification.flags & Notification.FLAG_INSISTENT) != 0;
                             int audioStreamType;
                             if (notification.audioStreamType >= 0) {
                                 audioStreamType = notification.audioStreamType;
@@ -1880,11 +1885,12 @@
                             mSoundNotification = r;
                             // do not play notifications if stream volume is 0 (typically because
                             // ringer mode is silent) or if there is a user of exclusive audio focus
-                            if ((audioManager.getStreamVolume(audioStreamType) != 0)
-                                    && !audioManager.isAudioFocusExclusive()) {
+                            if ((mAudioManager.getStreamVolume(audioStreamType) != 0)
+                                    && !mAudioManager.isAudioFocusExclusive()) {
                                 final long identity = Binder.clearCallingIdentity();
                                 try {
-                                    final IRingtonePlayer player = mAudioService.getRingtonePlayer();
+                                    final IRingtonePlayer player =
+                                            mAudioManager.getRingtonePlayer();
                                     if (player != null) {
                                         player.playAsync(soundUri, user, looping, audioStreamType);
                                     }
@@ -1904,7 +1910,7 @@
                         final boolean convertSoundToVibration =
                                    !hasCustomVibrate
                                 && hasValidSound
-                                && (audioManager.getRingerMode()
+                                && (mAudioManager.getRingerMode()
                                            == AudioManager.RINGER_MODE_VIBRATE);
 
                         // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
@@ -1912,7 +1918,7 @@
                                 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
 
                         if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate)
-                                && !(audioManager.getRingerMode()
+                                && !(mAudioManager.getRingerMode()
                                         == AudioManager.RINGER_MODE_SILENT)) {
                             mVibrateNotification = r;
 
@@ -1966,8 +1972,158 @@
         idOut[0] = id;
     }
 
-    private void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
-        AccessibilityManager manager = AccessibilityManager.getInstance(mContext);
+     void registerListenerImpl(final INotificationListener listener,
+            final ComponentName component, final int userid) {
+        synchronized (mNotificationList) {
+            try {
+                NotificationListenerInfo info
+                        = new NotificationListenerInfo(listener, component, userid, true);
+                listener.asBinder().linkToDeath(info, 0);
+                mListeners.add(info);
+            } catch (RemoteException e) {
+                // already dead
+            }
+        }
+    }
+
+    void unregisterListenerImpl(final INotificationListener listener, final int userid) {
+        synchronized (mNotificationList) {
+            final int N = mListeners.size();
+            for (int i=N-1; i>=0; i--) {
+                final NotificationListenerInfo info = mListeners.get(i);
+                if (info.listener.asBinder() == listener.asBinder()
+                        && info.userid == userid) {
+                    mListeners.remove(i);
+                    if (info.connection != null) {
+                        getContext().unbindService(info.connection);
+                    }
+                }
+            }
+        }
+    }
+
+    void showNextToastLocked() {
+        ToastRecord record = mToastQueue.get(0);
+        while (record != null) {
+            if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
+            try {
+                record.callback.show();
+                scheduleTimeoutLocked(record);
+                return;
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Object died trying to show notification " + record.callback
+                        + " in package " + record.pkg);
+                // remove it from the list and let the process die
+                int index = mToastQueue.indexOf(record);
+                if (index >= 0) {
+                    mToastQueue.remove(index);
+                }
+                keepProcessAliveLocked(record.pid);
+                if (mToastQueue.size() > 0) {
+                    record = mToastQueue.get(0);
+                } else {
+                    record = null;
+                }
+            }
+        }
+    }
+
+    void cancelToastLocked(int index) {
+        ToastRecord record = mToastQueue.get(index);
+        try {
+            record.callback.hide();
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Object died trying to hide notification " + record.callback
+                    + " in package " + record.pkg);
+            // don't worry about this, we're about to remove it from
+            // the list anyway
+        }
+        mToastQueue.remove(index);
+        keepProcessAliveLocked(record.pid);
+        if (mToastQueue.size() > 0) {
+            // Show the next one. If the callback fails, this will remove
+            // it from the list, so don't assume that the list hasn't changed
+            // after this point.
+            showNextToastLocked();
+        }
+    }
+
+    private void scheduleTimeoutLocked(ToastRecord r)
+    {
+        mHandler.removeCallbacksAndMessages(r);
+        Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
+        long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
+        mHandler.sendMessageDelayed(m, delay);
+    }
+
+    private void handleTimeout(ToastRecord record)
+    {
+        if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
+        synchronized (mToastQueue) {
+            int index = indexOfToastLocked(record.pkg, record.callback);
+            if (index >= 0) {
+                cancelToastLocked(index);
+            }
+        }
+    }
+
+    // lock on mToastQueue
+    int indexOfToastLocked(String pkg, ITransientNotification callback)
+    {
+        IBinder cbak = callback.asBinder();
+        ArrayList<ToastRecord> list = mToastQueue;
+        int len = list.size();
+        for (int i=0; i<len; i++) {
+            ToastRecord r = list.get(i);
+            if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    // lock on mToastQueue
+    void keepProcessAliveLocked(int pid)
+    {
+        int toastCount = 0; // toasts from this pid
+        ArrayList<ToastRecord> list = mToastQueue;
+        int N = list.size();
+        for (int i=0; i<N; i++) {
+            ToastRecord r = list.get(i);
+            if (r.pid == pid) {
+                toastCount++;
+            }
+        }
+        try {
+            mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
+        } catch (RemoteException e) {
+            // Shouldn't happen.
+        }
+    }
+
+    private final class WorkerHandler extends Handler
+    {
+        @Override
+        public void handleMessage(Message msg)
+        {
+            switch (msg.what)
+            {
+                case MESSAGE_TIMEOUT:
+                    handleTimeout((ToastRecord)msg.obj);
+                    break;
+            }
+        }
+    }
+
+
+    // Notifications
+    // ============================================================================
+    static int clamp(int x, int low, int high) {
+        return (x < low) ? low : ((x > high) ? high : x);
+    }
+
+    void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
+        AccessibilityManager manager = AccessibilityManager.getInstance(getContext());
         if (!manager.isEnabled()) {
             return;
         }
@@ -2001,11 +2157,10 @@
 
         // status bar
         if (r.getNotification().icon != 0) {
-            long identity = Binder.clearCallingIdentity();
+            final long identity = Binder.clearCallingIdentity();
             try {
                 mStatusBar.removeNotification(r.statusBarKey);
-            }
-            finally {
+            } finally {
                 Binder.restoreCallingIdentity(identity);
             }
             r.statusBarKey = null;
@@ -2017,7 +2172,7 @@
             mSoundNotification = null;
             final long identity = Binder.clearCallingIdentity();
             try {
-                final IRingtonePlayer player = mAudioService.getRingtonePlayer();
+                final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
                 if (player != null) {
                     player.stopAsync();
                 }
@@ -2053,7 +2208,7 @@
      * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
      * and none of the {@code mustNotHaveFlags}.
      */
-    private void cancelNotification(final String pkg, final String tag, final int id,
+    void cancelNotification(final String pkg, final String tag, final int id,
             final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
             final int userId) {
         // In enqueueNotificationInternal notifications are added by scheduling the
@@ -2146,26 +2301,7 @@
         }
     }
 
-    public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
-        checkCallerIsSystemOrSameApp(pkg);
-        userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
-                Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
-        // Don't allow client applications to cancel foreground service notis.
-        cancelNotification(pkg, tag, id, 0,
-                Binder.getCallingUid() == Process.SYSTEM_UID
-                ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false, userId);
-    }
 
-    public void cancelAllNotifications(String pkg, int userId) {
-        checkCallerIsSystemOrSameApp(pkg);
-
-        userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
-                Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
-
-        // Calling from user space, don't allow the canceling of actively
-        // running foreground services.
-        cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId);
-    }
 
     // Return true if the UID is a system or phone UID and therefore should not have
     // any notifications or toasts blocked.
@@ -2225,7 +2361,7 @@
     }
 
     // lock on mNotificationList
-    private void updateLightsLocked()
+    void updateLightsLocked()
     {
         // handle notification lights
         if (mLedNotification == null) {
@@ -2251,14 +2387,14 @@
             }
             if (mNotificationPulseEnabled) {
                 // pulse repeatedly
-                mNotificationLight.setFlashing(ledARGB, LightsService.LIGHT_FLASH_TIMED,
+                mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED,
                         ledOnMS, ledOffMS);
             }
         }
     }
 
     // lock on mNotificationList
-    private int indexOfNotificationLocked(String pkg, String tag, int id, int userId)
+    int indexOfNotificationLocked(String pkg, String tag, int id, int userId)
     {
         ArrayList<NotificationRecord> list = mNotificationList;
         final int len = list.size();
@@ -2288,81 +2424,4 @@
             updateLightsLocked();
         }
     }
-
-    // ======================================================================
-    @Override
-    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
-                != PackageManager.PERMISSION_GRANTED) {
-            pw.println("Permission Denial: can't dump NotificationManager from from pid="
-                    + Binder.getCallingPid()
-                    + ", uid=" + Binder.getCallingUid());
-            return;
-        }
-
-        pw.println("Current Notification Manager state:");
-
-        pw.println("  Listeners (" + mEnabledListenersForCurrentUser.size()
-                + ") enabled for current user:");
-        for (ComponentName cmpt : mEnabledListenersForCurrentUser) {
-            pw.println("    " + cmpt);
-        }
-
-        pw.println("  Live listeners (" + mListeners.size() + "):");
-        for (NotificationListenerInfo info : mListeners) {
-            pw.println("    " + info.component
-                    + " (user " + info.userid + "): " + info.listener
-                    + (info.isSystem?" SYSTEM":""));
-        }
-
-        int N;
-
-        synchronized (mToastQueue) {
-            N = mToastQueue.size();
-            if (N > 0) {
-                pw.println("  Toast Queue:");
-                for (int i=0; i<N; i++) {
-                    mToastQueue.get(i).dump(pw, "    ");
-                }
-                pw.println("  ");
-            }
-
-        }
-
-        synchronized (mNotificationList) {
-            N = mNotificationList.size();
-            if (N > 0) {
-                pw.println("  Notification List:");
-                for (int i=0; i<N; i++) {
-                    mNotificationList.get(i).dump(pw, "    ", mContext);
-                }
-                pw.println("  ");
-            }
-
-            N = mLights.size();
-            if (N > 0) {
-                pw.println("  Lights List:");
-                for (int i=0; i<N; i++) {
-                    pw.println("    " + mLights.get(i));
-                }
-                pw.println("  ");
-            }
-
-            pw.println("  mSoundNotification=" + mSoundNotification);
-            pw.println("  mVibrateNotification=" + mVibrateNotification);
-            pw.println("  mDisabledNotifications=0x" + Integer.toHexString(mDisabledNotifications));
-            pw.println("  mSystemReady=" + mSystemReady);
-            pw.println("  mArchive=" + mArchive.toString());
-            Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
-            int i=0;
-            while (iter.hasNext()) {
-                pw.println("    " + iter.next());
-                if (++i >= 5) {
-                    if (iter.hasNext()) pw.println("    ...");
-                    break;
-                }
-            }
-
-        }
-    }
 }
diff --git a/services/java/com/android/server/os/SchedulingPolicyService.java b/services/core/java/com/android/server/os/SchedulingPolicyService.java
similarity index 100%
rename from services/java/com/android/server/os/SchedulingPolicyService.java
rename to services/core/java/com/android/server/os/SchedulingPolicyService.java
diff --git a/services/java/com/android/server/pm/BasePermission.java b/services/core/java/com/android/server/pm/BasePermission.java
similarity index 100%
rename from services/java/com/android/server/pm/BasePermission.java
rename to services/core/java/com/android/server/pm/BasePermission.java
diff --git a/services/java/com/android/server/pm/GrantedPermissions.java b/services/core/java/com/android/server/pm/GrantedPermissions.java
similarity index 100%
rename from services/java/com/android/server/pm/GrantedPermissions.java
rename to services/core/java/com/android/server/pm/GrantedPermissions.java
diff --git a/services/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
similarity index 100%
rename from services/java/com/android/server/pm/Installer.java
rename to services/core/java/com/android/server/pm/Installer.java
diff --git a/services/java/com/android/server/pm/KeySetManager.java b/services/core/java/com/android/server/pm/KeySetManager.java
similarity index 100%
rename from services/java/com/android/server/pm/KeySetManager.java
rename to services/core/java/com/android/server/pm/KeySetManager.java
diff --git a/services/java/com/android/server/pm/PackageKeySetData.java b/services/core/java/com/android/server/pm/PackageKeySetData.java
similarity index 100%
rename from services/java/com/android/server/pm/PackageKeySetData.java
rename to services/core/java/com/android/server/pm/PackageKeySetData.java
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
similarity index 99%
rename from services/java/com/android/server/pm/PackageManagerService.java
rename to services/core/java/com/android/server/pm/PackageManagerService.java
index 5761f6c..b11ebf5 100755
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -38,10 +38,10 @@
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.XmlUtils;
-import com.android.server.DeviceStorageMonitorService;
 import com.android.server.EventLogTags;
 import com.android.server.IntentResolver;
 
+import com.android.server.LocalServices;
 import com.android.server.Watchdog;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -92,6 +92,7 @@
 import android.content.pm.VerifierDeviceIdentity;
 import android.content.pm.VerifierInfo;
 import android.content.res.Resources;
+import android.hardware.display.DisplayManager;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
@@ -127,7 +128,6 @@
 import android.util.SparseArray;
 import android.util.Xml;
 import android.view.Display;
-import android.view.WindowManager;
 
 import java.io.BufferedOutputStream;
 import java.io.File;
@@ -162,6 +162,7 @@
 import libcore.io.StructStat;
 
 import com.android.internal.R;
+import com.android.server.storage.DeviceStorageMonitorInternal;
 
 /**
  * Keep track of all those .apks everywhere.
@@ -1067,6 +1068,12 @@
         return res;
     }
 
+    private static void getDefaultDisplayMetrics(Context context, DisplayMetrics metrics) {
+        DisplayManager displayManager = (DisplayManager) context.getSystemService(
+                Context.DISPLAY_SERVICE);
+        displayManager.getDisplay(Display.DEFAULT_DISPLAY).getMetrics(metrics);
+    }
+
     public PackageManagerService(Context context, Installer installer,
             boolean factoryTest, boolean onlyCore) {
         EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
@@ -1114,9 +1121,7 @@
 
         mInstaller = installer;
 
-        WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
-        Display d = wm.getDefaultDisplay();
-        d.getMetrics(mMetrics);
+        getDefaultDisplayMetrics(context, mMetrics);
 
         synchronized (mInstallLock) {
         // writer
@@ -7339,6 +7344,15 @@
             return pkgLite.recommendedInstallLocation;
         }
 
+        private long getMemoryLowThreshold() {
+            final DeviceStorageMonitorInternal
+                    dsm = LocalServices.getService(DeviceStorageMonitorInternal.class);
+            if (dsm == null) {
+                return 0L;
+            }
+            return dsm.getMemoryLowThreshold();
+        }
+
         /*
          * Invoke remote method to get package information and install
          * location values. Override install location based on default
@@ -7356,15 +7370,9 @@
                 Slog.w(TAG, "Conflicting flags specified for installing on both internal and external");
                 ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
             } else {
-                final long lowThreshold;
-
-                final DeviceStorageMonitorService dsm = (DeviceStorageMonitorService) ServiceManager
-                        .getService(DeviceStorageMonitorService.SERVICE);
-                if (dsm == null) {
+                final long lowThreshold = getMemoryLowThreshold();
+                if (lowThreshold == 0L) {
                     Log.w(TAG, "Couldn't get low memory threshold; no free limit imposed");
-                    lowThreshold = 0L;
-                } else {
-                    lowThreshold = dsm.getMemoryLowThreshold();
                 }
 
                 try {
@@ -7922,8 +7930,8 @@
         boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException {
             final long lowThreshold;
 
-            final DeviceStorageMonitorService dsm = (DeviceStorageMonitorService) ServiceManager
-                    .getService(DeviceStorageMonitorService.SERVICE);
+            final DeviceStorageMonitorInternal
+                    dsm = LocalServices.getService(DeviceStorageMonitorInternal.class);
             if (dsm == null) {
                 Log.w(TAG, "Couldn't get low memory threshold; no free limit imposed");
                 lowThreshold = 0L;
@@ -9738,10 +9746,10 @@
                 clearExternalStorageDataSync(packageName, userId, true);
                 if (succeeded) {
                     // invoke DeviceStorageMonitor's update method to clear any notifications
-                    DeviceStorageMonitorService dsm = (DeviceStorageMonitorService)
-                            ServiceManager.getService(DeviceStorageMonitorService.SERVICE);
+                    DeviceStorageMonitorInternal
+                            dsm = LocalServices.getService(DeviceStorageMonitorInternal.class);
                     if (dsm != null) {
-                        dsm.updateMemory();
+                        dsm.checkMemory();
                     }
                 }
                 if(observer != null) {
@@ -11566,12 +11574,17 @@
         return true;
     }
 
+    @Override
     public boolean isStorageLow() {
         final long token = Binder.clearCallingIdentity();
         try {
-            final DeviceStorageMonitorService dsm = (DeviceStorageMonitorService) ServiceManager
-                    .getService(DeviceStorageMonitorService.SERVICE);
-            return dsm.isMemoryLow();
+            final DeviceStorageMonitorInternal
+                    dsm = LocalServices.getService(DeviceStorageMonitorInternal.class);
+            if (dsm != null) {
+                return dsm.isMemoryLow();
+            } else {
+                return false;
+            }
         } finally {
             Binder.restoreCallingIdentity(token);
         }
diff --git a/services/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
similarity index 100%
rename from services/java/com/android/server/pm/PackageSetting.java
rename to services/core/java/com/android/server/pm/PackageSetting.java
diff --git a/services/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
similarity index 100%
rename from services/java/com/android/server/pm/PackageSettingBase.java
rename to services/core/java/com/android/server/pm/PackageSettingBase.java
diff --git a/services/java/com/android/server/pm/PackageSignatures.java b/services/core/java/com/android/server/pm/PackageSignatures.java
similarity index 100%
rename from services/java/com/android/server/pm/PackageSignatures.java
rename to services/core/java/com/android/server/pm/PackageSignatures.java
diff --git a/services/java/com/android/server/pm/PackageVerificationResponse.java b/services/core/java/com/android/server/pm/PackageVerificationResponse.java
similarity index 100%
rename from services/java/com/android/server/pm/PackageVerificationResponse.java
rename to services/core/java/com/android/server/pm/PackageVerificationResponse.java
diff --git a/services/java/com/android/server/pm/PackageVerificationState.java b/services/core/java/com/android/server/pm/PackageVerificationState.java
similarity index 100%
rename from services/java/com/android/server/pm/PackageVerificationState.java
rename to services/core/java/com/android/server/pm/PackageVerificationState.java
diff --git a/services/java/com/android/server/pm/PendingPackage.java b/services/core/java/com/android/server/pm/PendingPackage.java
similarity index 100%
rename from services/java/com/android/server/pm/PendingPackage.java
rename to services/core/java/com/android/server/pm/PendingPackage.java
diff --git a/services/java/com/android/server/pm/PreferredActivity.java b/services/core/java/com/android/server/pm/PreferredActivity.java
similarity index 98%
rename from services/java/com/android/server/pm/PreferredActivity.java
rename to services/core/java/com/android/server/pm/PreferredActivity.java
index f93ba2f..8916926 100644
--- a/services/java/com/android/server/pm/PreferredActivity.java
+++ b/services/core/java/com/android/server/pm/PreferredActivity.java
@@ -17,7 +17,6 @@
 package com.android.server.pm;
 
 import com.android.internal.util.XmlUtils;
-import com.android.server.PreferredComponent;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/java/com/android/server/PreferredComponent.java b/services/core/java/com/android/server/pm/PreferredComponent.java
similarity index 99%
rename from services/java/com/android/server/PreferredComponent.java
rename to services/core/java/com/android/server/pm/PreferredComponent.java
index a7af252..f437372 100644
--- a/services/java/com/android/server/PreferredComponent.java
+++ b/services/core/java/com/android/server/pm/PreferredComponent.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.pm;
 
 import com.android.internal.util.XmlUtils;
 
diff --git a/services/java/com/android/server/pm/PreferredIntentResolver.java b/services/core/java/com/android/server/pm/PreferredIntentResolver.java
similarity index 100%
rename from services/java/com/android/server/pm/PreferredIntentResolver.java
rename to services/core/java/com/android/server/pm/PreferredIntentResolver.java
diff --git a/services/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
similarity index 100%
rename from services/java/com/android/server/pm/SELinuxMMAC.java
rename to services/core/java/com/android/server/pm/SELinuxMMAC.java
diff --git a/services/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
similarity index 100%
rename from services/java/com/android/server/pm/Settings.java
rename to services/core/java/com/android/server/pm/Settings.java
diff --git a/services/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
similarity index 100%
rename from services/java/com/android/server/pm/SharedUserSetting.java
rename to services/core/java/com/android/server/pm/SharedUserSetting.java
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
similarity index 100%
rename from services/java/com/android/server/pm/UserManagerService.java
rename to services/core/java/com/android/server/pm/UserManagerService.java
diff --git a/services/java/com/android/server/power/DisplayBlanker.java b/services/core/java/com/android/server/power/DisplayBlanker.java
similarity index 100%
rename from services/java/com/android/server/power/DisplayBlanker.java
rename to services/core/java/com/android/server/power/DisplayBlanker.java
diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/core/java/com/android/server/power/DisplayPowerController.java
similarity index 98%
rename from services/java/com/android/server/power/DisplayPowerController.java
rename to services/core/java/com/android/server/power/DisplayPowerController.java
index 60d44c7..b8a78e3 100644
--- a/services/java/com/android/server/power/DisplayPowerController.java
+++ b/services/core/java/com/android/server/power/DisplayPowerController.java
@@ -16,10 +16,11 @@
 
 package com.android.server.power;
 
-import com.android.server.LightsService;
-import com.android.server.TwilightService;
-import com.android.server.TwilightService.TwilightState;
+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;
 import android.animation.ObjectAnimator;
@@ -179,10 +180,10 @@
     private Handler mCallbackHandler;
 
     // The lights service.
-    private final LightsService mLights;
+    private final LightsManager mLights;
 
     // The twilight service.
-    private final TwilightService mTwilight;
+    private final TwilightManager mTwilight;
 
     // The display manager.
     private final DisplayManagerService mDisplayManager;
@@ -351,7 +352,7 @@
      * Creates the display power controller.
      */
     public DisplayPowerController(Looper looper, Context context, Notifier notifier,
-            LightsService lights, TwilightService twilight, SensorManager sensorManager,
+            LightsManager lights, TwilightManager twilight, SensorManager sensorManager,
             DisplayManagerService displayManager,
             SuspendBlocker displaySuspendBlocker, DisplayBlanker displayBlanker,
             Callbacks callbacks, Handler callbackHandler) {
@@ -528,7 +529,7 @@
     private void initialize() {
         mPowerState = new DisplayPowerState(
                 new ElectronBeam(mDisplayManager), mDisplayBlanker,
-                mLights.getLight(LightsService.LIGHT_ID_BACKLIGHT));
+                mLights.getLight(LightsManager.LIGHT_ID_BACKLIGHT));
 
         mElectronBeamOnAnimator = ObjectAnimator.ofFloat(
                 mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 0.0f, 1.0f);
@@ -1368,8 +1369,7 @@
         }
     };
 
-    private final TwilightService.TwilightListener mTwilightListener =
-            new TwilightService.TwilightListener() {
+    private final TwilightListener mTwilightListener = new TwilightListener() {
         @Override
         public void onTwilightStateChanged() {
             mTwilightChanged = true;
diff --git a/services/java/com/android/server/power/DisplayPowerRequest.java b/services/core/java/com/android/server/power/DisplayPowerRequest.java
similarity index 100%
rename from services/java/com/android/server/power/DisplayPowerRequest.java
rename to services/core/java/com/android/server/power/DisplayPowerRequest.java
diff --git a/services/java/com/android/server/power/DisplayPowerState.java b/services/core/java/com/android/server/power/DisplayPowerState.java
similarity index 98%
rename from services/java/com/android/server/power/DisplayPowerState.java
rename to services/core/java/com/android/server/power/DisplayPowerState.java
index fa318f8..42af4b4 100644
--- a/services/java/com/android/server/power/DisplayPowerState.java
+++ b/services/core/java/com/android/server/power/DisplayPowerState.java
@@ -16,7 +16,7 @@
 
 package com.android.server.power;
 
-import com.android.server.LightsService;
+import com.android.server.lights.Light;
 
 import android.os.AsyncTask;
 import android.os.Handler;
@@ -56,7 +56,7 @@
     private final Choreographer mChoreographer;
     private final ElectronBeam mElectronBeam;
     private final DisplayBlanker mDisplayBlanker;
-    private final LightsService.Light mBacklight;
+    private final Light mBacklight;
     private final PhotonicModulator mPhotonicModulator;
 
     private boolean mScreenOn;
@@ -72,7 +72,7 @@
     private Runnable mCleanListener;
 
     public DisplayPowerState(ElectronBeam electronBean,
-            DisplayBlanker displayBlanker, LightsService.Light backlight) {
+            DisplayBlanker displayBlanker, Light backlight) {
         mHandler = new Handler(true /*async*/);
         mChoreographer = Choreographer.getInstance();
         mElectronBeam = electronBean;
diff --git a/services/java/com/android/server/power/ElectronBeam.java b/services/core/java/com/android/server/power/ElectronBeam.java
similarity index 100%
rename from services/java/com/android/server/power/ElectronBeam.java
rename to services/core/java/com/android/server/power/ElectronBeam.java
diff --git a/services/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
similarity index 100%
rename from services/java/com/android/server/power/Notifier.java
rename to services/core/java/com/android/server/power/Notifier.java
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
similarity index 98%
rename from services/java/com/android/server/power/PowerManagerService.java
rename to services/core/java/com/android/server/power/PowerManagerService.java
index da9548f..13f55e2 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -20,10 +20,11 @@
 import com.android.internal.app.IBatteryStats;
 import com.android.server.BatteryService;
 import com.android.server.EventLogTags;
-import com.android.server.LightsService;
-import com.android.server.TwilightService;
+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.am.ActivityManagerService;
 import com.android.server.display.DisplayManagerService;
 import com.android.server.dreams.DreamManagerService;
 
@@ -168,7 +169,7 @@
     private static final int DREAM_BATTERY_LEVEL_DRAIN_CUTOFF = 5;
 
     private Context mContext;
-    private LightsService mLightsService;
+    private LightsManager mLightsManager;
     private BatteryService mBatteryService;
     private DisplayManagerService mDisplayManagerService;
     private IBatteryStats mBatteryStats;
@@ -181,7 +182,7 @@
     private WirelessChargerDetector mWirelessChargerDetector;
     private SettingsObserver mSettingsObserver;
     private DreamManagerService mDreamManager;
-    private LightsService.Light mAttentionLight;
+    private Light mAttentionLight;
 
     private final Object mLock = new Object();
 
@@ -396,11 +397,11 @@
      * Initialize the power manager.
      * Must be called before any other functions within the power manager are called.
      */
-    public void init(Context context, LightsService ls,
-            ActivityManagerService am, BatteryService bs, IBatteryStats bss,
+    public void init(Context context, LightsManager ls,
+            BatteryService bs, IBatteryStats bss,
             IAppOpsService appOps, DisplayManagerService dm) {
         mContext = context;
-        mLightsService = ls;
+        mLightsManager = ls;
         mBatteryService = bs;
         mBatteryStats = bss;
         mAppOps = appOps;
@@ -427,12 +428,12 @@
         }
     }
 
-    public void systemReady(TwilightService twilight, DreamManagerService dreamManager) {
+    public void systemReady(TwilightManager twilight, DreamManagerService dreamManager) {
         synchronized (mLock) {
             mSystemReady = true;
             mDreamManager = dreamManager;
 
-            PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+            PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
             mScreenBrightnessSettingMinimum = pm.getMinimumScreenBrightnessSetting();
             mScreenBrightnessSettingMaximum = pm.getMaximumScreenBrightnessSetting();
             mScreenBrightnessSettingDefault = pm.getDefaultScreenBrightnessSetting();
@@ -448,7 +449,7 @@
             // The display power controller runs on the power manager service's
             // own handler thread to ensure timely operation.
             mDisplayPowerController = new DisplayPowerController(mHandler.getLooper(),
-                    mContext, mNotifier, mLightsService, twilight, sensorManager,
+                    mContext, mNotifier, mLightsManager, twilight, sensorManager,
                     mDisplayManagerService, mDisplaySuspendBlocker, mDisplayBlanker,
                     mDisplayPowerControllerCallbacks, mHandler);
 
@@ -456,7 +457,7 @@
                     createSuspendBlockerLocked("PowerManagerService.WirelessChargerDetector"),
                     mHandler);
             mSettingsObserver = new SettingsObserver(mHandler);
-            mAttentionLight = mLightsService.getLight(LightsService.LIGHT_ID_ATTENTION);
+            mAttentionLight = mLightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
 
             // Register for broadcasts from other components of the system.
             IntentFilter filter = new IntentFilter();
@@ -2061,7 +2062,7 @@
     }
 
     private void setAttentionLightInternal(boolean on, int color) {
-        LightsService.Light light;
+        Light light;
         synchronized (mLock) {
             if (!mSystemReady) {
                 return;
@@ -2070,7 +2071,7 @@
         }
 
         // Control light outside of lock.
-        light.setFlashing(color, LightsService.LIGHT_FLASH_HARDWARE, (on ? 3 : 0), 0);
+        light.setFlashing(color, Light.LIGHT_FLASH_HARDWARE, (on ? 3 : 0), 0);
     }
 
     /**
diff --git a/services/java/com/android/server/power/RampAnimator.java b/services/core/java/com/android/server/power/RampAnimator.java
similarity index 100%
rename from services/java/com/android/server/power/RampAnimator.java
rename to services/core/java/com/android/server/power/RampAnimator.java
diff --git a/services/java/com/android/server/power/ScreenOnBlocker.java b/services/core/java/com/android/server/power/ScreenOnBlocker.java
similarity index 100%
rename from services/java/com/android/server/power/ScreenOnBlocker.java
rename to services/core/java/com/android/server/power/ScreenOnBlocker.java
diff --git a/services/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
similarity index 100%
rename from services/java/com/android/server/power/ShutdownThread.java
rename to services/core/java/com/android/server/power/ShutdownThread.java
diff --git a/services/java/com/android/server/power/SuspendBlocker.java b/services/core/java/com/android/server/power/SuspendBlocker.java
similarity index 100%
rename from services/java/com/android/server/power/SuspendBlocker.java
rename to services/core/java/com/android/server/power/SuspendBlocker.java
diff --git a/services/java/com/android/server/power/WirelessChargerDetector.java b/services/core/java/com/android/server/power/WirelessChargerDetector.java
similarity index 100%
rename from services/java/com/android/server/power/WirelessChargerDetector.java
rename to services/core/java/com/android/server/power/WirelessChargerDetector.java
diff --git a/services/java/com/android/server/search/SearchManagerService.java b/services/core/java/com/android/server/search/SearchManagerService.java
similarity index 100%
rename from services/java/com/android/server/search/SearchManagerService.java
rename to services/core/java/com/android/server/search/SearchManagerService.java
diff --git a/services/java/com/android/server/search/Searchables.java b/services/core/java/com/android/server/search/Searchables.java
similarity index 100%
rename from services/java/com/android/server/search/Searchables.java
rename to services/core/java/com/android/server/search/Searchables.java
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
new file mode 100644
index 0000000..4f75189
--- /dev/null
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -0,0 +1,29 @@
+/**
+ * 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.statusbar;
+
+import com.android.server.notification.NotificationDelegate;
+
+import android.os.IBinder;
+import android.service.notification.StatusBarNotification;
+
+public interface StatusBarManagerInternal {
+    void setNotificationDelegate(NotificationDelegate delegate);
+    IBinder addNotification(StatusBarNotification notification);
+    void updateNotification(IBinder key, StatusBarNotification notification);
+    void removeNotification(IBinder key);
+}
diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
similarity index 80%
rename from services/java/com/android/server/StatusBarManagerService.java
rename to services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index f207c08..2ae467e 100644
--- a/services/java/com/android/server/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -14,26 +14,28 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.statusbar;
 
 import android.app.StatusBarManager;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.UserHandle;
 import android.util.Slog;
 
 import com.android.internal.statusbar.IStatusBar;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.statusbar.StatusBarIconList;
+import com.android.server.LocalServices;
+import com.android.server.notification.NotificationDelegate;
 import com.android.server.wm.WindowManagerService;
 
 import java.io.FileDescriptor;
@@ -51,31 +53,31 @@
 public class StatusBarManagerService extends IStatusBarService.Stub
     implements WindowManagerService.OnHardKeyboardStatusChangeListener
 {
-    static final String TAG = "StatusBarManagerService";
-    static final boolean SPEW = false;
+    private static final String TAG = "StatusBarManagerService";
+    private static final boolean SPEW = false;
 
-    final Context mContext;
-    final WindowManagerService mWindowManager;
-    Handler mHandler = new Handler();
-    NotificationCallbacks mNotificationCallbacks;
-    volatile IStatusBar mBar;
-    StatusBarIconList mIcons = new StatusBarIconList();
-    HashMap<IBinder,StatusBarNotification> mNotifications
+    private final Context mContext;
+    private final WindowManagerService mWindowManager;
+    private Handler mHandler = new Handler();
+    private NotificationDelegate mNotificationDelegate;
+    private volatile IStatusBar mBar;
+    private StatusBarIconList mIcons = new StatusBarIconList();
+    private HashMap<IBinder,StatusBarNotification> mNotifications
             = new HashMap<IBinder,StatusBarNotification>();
 
     // for disabling the status bar
-    final ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>();
-    IBinder mSysUiVisToken = new Binder();
-    int mDisabled = 0;
+    private final ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>();
+    private IBinder mSysUiVisToken = new Binder();
+    private int mDisabled = 0;
 
-    Object mLock = new Object();
+    private Object mLock = new Object();
     // encompasses lights-out mode and other flags defined on View
-    int mSystemUiVisibility = 0;
-    boolean mMenuVisible = false;
-    int mImeWindowVis = 0;
-    int mImeBackDisposition;
-    IBinder mImeToken = null;
-    int mCurrentUserId;
+    private int mSystemUiVisibility = 0;
+    private boolean mMenuVisible = false;
+    private int mImeWindowVis = 0;
+    private int mImeBackDisposition;
+    private IBinder mImeToken = null;
+    private int mCurrentUserId;
 
     private class DisableRecord implements IBinder.DeathRecipient {
         int userId;
@@ -90,16 +92,6 @@
         }
     }
 
-    public interface NotificationCallbacks {
-        void onSetDisabled(int status);
-        void onClearAll();
-        void onNotificationClick(String pkg, String tag, int id);
-        void onNotificationClear(String pkg, String tag, int id);
-        void onPanelRevealed();
-        void onNotificationError(String pkg, String tag, int id,
-                int uid, int initialPid, String message);
-    }
-
     /**
      * Construct the service, add the status bar view to the window manager
      */
@@ -110,15 +102,74 @@
 
         final Resources res = context.getResources();
         mIcons.defineSlots(res.getStringArray(com.android.internal.R.array.config_statusBarIcons));
+
+        LocalServices.addService(StatusBarManagerInternal.class, mInternalService);
     }
 
-    public void setNotificationCallbacks(NotificationCallbacks listener) {
-        mNotificationCallbacks = listener;
-    }
+    /**
+     * Private API used by NotificationManagerService.
+     */
+    private final StatusBarManagerInternal mInternalService = new StatusBarManagerInternal() {
+        @Override
+        public void setNotificationDelegate(NotificationDelegate delegate) {
+            synchronized (mNotifications) {
+                mNotificationDelegate = delegate;
+            }
+        }
+
+        @Override
+        public IBinder addNotification(StatusBarNotification notification) {
+            synchronized (mNotifications) {
+                IBinder key = new Binder();
+                mNotifications.put(key, notification);
+                if (mBar != null) {
+                    try {
+                        mBar.addNotification(key, notification);
+                    } catch (RemoteException ex) {
+                    }
+                }
+                return key;
+            }
+        }
+
+        @Override
+        public void updateNotification(IBinder key, StatusBarNotification notification) {
+            synchronized (mNotifications) {
+                if (!mNotifications.containsKey(key)) {
+                    throw new IllegalArgumentException("updateNotification key not found: " + key);
+                }
+                mNotifications.put(key, notification);
+                if (mBar != null) {
+                    try {
+                        mBar.updateNotification(key, notification);
+                    } catch (RemoteException ex) {
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void removeNotification(IBinder key) {
+            synchronized (mNotifications) {
+                final StatusBarNotification n = mNotifications.remove(key);
+                if (n == null) {
+                    Slog.e(TAG, "removeNotification key not found: " + key);
+                    return;
+                }
+                if (mBar != null) {
+                    try {
+                        mBar.removeNotification(key);
+                    } catch (RemoteException ex) {
+                    }
+                }
+            }
+        }
+    };
 
     // ================================================================================
     // From IStatusBarService
     // ================================================================================
+    @Override
     public void expandNotificationsPanel() {
         enforceExpandStatusBar();
 
@@ -130,6 +181,7 @@
         }
     }
 
+    @Override
     public void collapsePanels() {
         enforceExpandStatusBar();
 
@@ -141,6 +193,7 @@
         }
     }
 
+    @Override
     public void expandSettingsPanel() {
         enforceExpandStatusBar();
 
@@ -152,6 +205,7 @@
         }
     }
 
+    @Override
     public void disable(int what, IBinder token, String pkg) {
         disableInternal(mCurrentUserId, what, token, pkg);
     }
@@ -177,7 +231,7 @@
             mDisabled = net;
             mHandler.post(new Runnable() {
                     public void run() {
-                        mNotificationCallbacks.onSetDisabled(net);
+                        mNotificationDelegate.onSetDisabled(net);
                     }
                 });
             if (mBar != null) {
@@ -189,6 +243,7 @@
         }
     }
 
+    @Override
     public void setIcon(String slot, String iconPackage, int iconId, int iconLevel,
             String contentDescription) {
         enforceStatusBar();
@@ -214,6 +269,7 @@
         }
     }
 
+    @Override
     public void setIconVisibility(String slot, boolean visible) {
         enforceStatusBar();
 
@@ -241,6 +297,7 @@
         }
     }
 
+    @Override
     public void removeIcon(String slot) {
         enforceStatusBar();
 
@@ -265,6 +322,7 @@
      * Hide or show the on-screen Menu key. Only call this from the window manager, typically in
      * response to a window with FLAG_NEEDS_MENU_KEY set.
      */
+    @Override
     public void topAppWindowChanged(final boolean menuVisible) {
         enforceStatusBar();
 
@@ -285,6 +343,7 @@
         }
     }
 
+    @Override
     public void setImeWindowStatus(final IBinder token, final int vis, final int backDisposition) {
         enforceStatusBar();
 
@@ -312,6 +371,7 @@
         }
     }
 
+    @Override
     public void setSystemUiVisibility(int vis, int mask) {
         // also allows calls from window manager which is in this process.
         enforceStatusBarService();
@@ -344,6 +404,7 @@
         }
     }
 
+    @Override
     public void setHardKeyboardEnabled(final boolean enabled) {
         mHandler.post(new Runnable() {
             public void run() {
@@ -426,6 +487,7 @@
     // ================================================================================
     // Callbacks from the status bar service.
     // ================================================================================
+    @Override
     public void registerStatusBar(IStatusBar bar, StatusBarIconList iconList,
             List<IBinder> notificationKeys, List<StatusBarNotification> notifications,
             int switches[], List<IBinder> binders) {
@@ -458,86 +520,64 @@
      * The status bar service should call this each time the user brings the panel from
      * invisible to visible in order to clear the notification light.
      */
+    @Override
     public void onPanelRevealed() {
         enforceStatusBarService();
-
-        // tell the notification manager to turn off the lights.
-        mNotificationCallbacks.onPanelRevealed();
+        long identity = Binder.clearCallingIdentity();
+        try {
+            // tell the notification manager to turn off the lights.
+            mNotificationDelegate.onPanelRevealed();
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
     }
 
+    @Override
     public void onNotificationClick(String pkg, String tag, int id) {
         enforceStatusBarService();
-
-        mNotificationCallbacks.onNotificationClick(pkg, tag, id);
+        long identity = Binder.clearCallingIdentity();
+        try {
+            mNotificationDelegate.onNotificationClick(pkg, tag, id);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
     }
 
+    @Override
     public void onNotificationError(String pkg, String tag, int id,
             int uid, int initialPid, String message) {
         enforceStatusBarService();
-
-        // WARNING: this will call back into us to do the remove.  Don't hold any locks.
-        mNotificationCallbacks.onNotificationError(pkg, tag, id, uid, initialPid, message);
+        long identity = Binder.clearCallingIdentity();
+        try {
+            // WARNING: this will call back into us to do the remove.  Don't hold any locks.
+            mNotificationDelegate.onNotificationError(pkg, tag, id, uid, initialPid, message);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
     }
 
+    @Override
     public void onNotificationClear(String pkg, String tag, int id) {
         enforceStatusBarService();
-
-        mNotificationCallbacks.onNotificationClear(pkg, tag, id);
+        long identity = Binder.clearCallingIdentity();
+        try {
+            mNotificationDelegate.onNotificationClear(pkg, tag, id);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
     }
 
+    @Override
     public void onClearAllNotifications() {
         enforceStatusBarService();
-
-        mNotificationCallbacks.onClearAll();
-    }
-
-    // ================================================================================
-    // Callbacks for NotificationManagerService.
-    // ================================================================================
-    public IBinder addNotification(StatusBarNotification notification) {
-        synchronized (mNotifications) {
-            IBinder key = new Binder();
-            mNotifications.put(key, notification);
-            if (mBar != null) {
-                try {
-                    mBar.addNotification(key, notification);
-                } catch (RemoteException ex) {
-                }
-            }
-            return key;
+        long identity = Binder.clearCallingIdentity();
+        try {
+            mNotificationDelegate.onClearAll();
+        } finally {
+            Binder.restoreCallingIdentity(identity);
         }
     }
 
-    public void updateNotification(IBinder key, StatusBarNotification notification) {
-        synchronized (mNotifications) {
-            if (!mNotifications.containsKey(key)) {
-                throw new IllegalArgumentException("updateNotification key not found: " + key);
-            }
-            mNotifications.put(key, notification);
-            if (mBar != null) {
-                try {
-                    mBar.updateNotification(key, notification);
-                } catch (RemoteException ex) {
-                }
-            }
-        }
-    }
-
-    public void removeNotification(IBinder key) {
-        synchronized (mNotifications) {
-            final StatusBarNotification n = mNotifications.remove(key);
-            if (n == null) {
-                Slog.e(TAG, "removeNotification key not found: " + key);
-                return;
-            }
-            if (mBar != null) {
-                try {
-                    mBar.removeNotification(key);
-                } catch (RemoteException ex) {
-                }
-            }
-        }
-    }
 
     // ================================================================================
     // Can be called from any thread
diff --git a/services/core/java/com/android/server/storage/DeviceStorageMonitorInternal.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorInternal.java
new file mode 100644
index 0000000..a91a81b
--- /dev/null
+++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorInternal.java
@@ -0,0 +1,24 @@
+/**
+ * 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.storage;
+
+public interface DeviceStorageMonitorInternal {
+    boolean isMemoryLow();
+    long getMemoryLowThreshold();
+    void checkMemory();
+}
+
diff --git a/services/java/com/android/server/DeviceStorageMonitorService.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
similarity index 79%
rename from services/java/com/android/server/DeviceStorageMonitorService.java
rename to services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
index 016c561..8805084 100644
--- a/services/java/com/android/server/DeviceStorageMonitorService.java
+++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
@@ -14,7 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.storage;
+
+import com.android.server.EventLogTags;
+import com.android.server.SystemService;
 
 import android.app.Notification;
 import android.app.NotificationManager;
@@ -29,8 +32,8 @@
 import android.os.Environment;
 import android.os.FileObserver;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Message;
-import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.StatFs;
@@ -66,13 +69,13 @@
  * settings parameter with a default value of 2MB), the free memory is
  * logged to the event log.
  */
-public class DeviceStorageMonitorService extends Binder {
-    private static final String TAG = "DeviceStorageMonitorService";
+public class DeviceStorageMonitorService extends SystemService {
+    static final String TAG = "DeviceStorageMonitorService";
 
-    private static final boolean DEBUG = false;
-    private static final boolean localLOGV = false;
+    static final boolean DEBUG = false;
+    static final boolean localLOGV = false;
 
-    private static final int DEVICE_MEMORY_WHAT = 1;
+    static final int DEVICE_MEMORY_WHAT = 1;
     private static final int MONITOR_INTERVAL = 1; //in minutes
     private static final int LOW_MEMORY_NOTIFICATION_ID = 1;
 
@@ -84,9 +87,8 @@
     private long mFreeMemAfterLastCacheClear;  // on /data
     private long mLastReportedFreeMem;
     private long mLastReportedFreeMemTime;
-    private boolean mLowMemFlag=false;
+    boolean mLowMemFlag=false;
     private boolean mMemFullFlag=false;
-    private Context mContext;
     private ContentResolver mResolver;
     private long mTotalMemory;  // on /data
     private StatFs mDataFileStats;
@@ -98,19 +100,19 @@
     private static final File CACHE_PATH = Environment.getDownloadCacheDirectory();
 
     private long mThreadStartTime = -1;
-    private boolean mClearSucceeded = false;
-    private boolean mClearingCache;
+    boolean mClearSucceeded = false;
+    boolean mClearingCache;
     private Intent mStorageLowIntent;
     private Intent mStorageOkIntent;
     private Intent mStorageFullIntent;
     private Intent mStorageNotFullIntent;
     private CachePackageDataObserver mClearCacheObserver;
-    private final CacheFileDeletedObserver mCacheFileDeletedObserver;
+    private CacheFileDeletedObserver mCacheFileDeletedObserver;
     private static final int _TRUE = 1;
     private static final int _FALSE = 0;
     // This is the raw threshold that has been set at which we consider
     // storage to be low.
-    private long mMemLowThreshold;
+    long mMemLowThreshold;
     // This is the threshold at which we start trying to flush caches
     // to get below the low threshold limit.  It is less than the low
     // threshold; we will allow storage to get a bit beyond the limit
@@ -126,13 +128,13 @@
     /**
      * This string is used for ServiceManager access to this class.
      */
-    public static final String SERVICE = "devicestoragemonitor";
+    static final String SERVICE = "devicestoragemonitor";
 
     /**
     * Handler that checks the amount of disk space on the device and sends a
     * notification if the device runs low on disk space
     */
-    Handler mHandler = new Handler() {
+    private Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
             //don't handle an invalid message
@@ -144,7 +146,7 @@
         }
     };
 
-    class CachePackageDataObserver extends IPackageDataObserver.Stub {
+    private class CachePackageDataObserver extends IPackageDataObserver.Stub {
         public void onRemoveCompleted(String packageName, boolean succeeded) {
             mClearSucceeded = succeeded;
             mClearingCache = false;
@@ -154,7 +156,7 @@
         }
     }
 
-    private final void restatDataDir() {
+    private void restatDataDir() {
         try {
             mDataFileStats.restat(DATA_PATH.getAbsolutePath());
             mFreeMem = (long) mDataFileStats.getAvailableBlocks() *
@@ -206,7 +208,7 @@
         }
     }
 
-    private final void clearCache() {
+    private void clearCache() {
         if (mClearCacheObserver == null) {
             // Lazy instantiation
             mClearCacheObserver = new CachePackageDataObserver();
@@ -223,7 +225,7 @@
         }
     }
 
-    private final void checkMemory(boolean checkCache) {
+    void checkMemory(boolean checkCache) {
         //if the thread that was started to clear cache is still running do nothing till its
         //finished clearing cache. Ideally this flag could be modified by clearCache
         // and should be accessed via a lock but even if it does this test will fail now and
@@ -300,7 +302,7 @@
         postCheckMemoryMsg(true, DEFAULT_CHECK_INTERVAL);
     }
 
-    private void postCheckMemoryMsg(boolean clearCache, long delay) {
+    void postCheckMemoryMsg(boolean clearCache, long delay) {
         // Remove queued messages
         mHandler.removeMessages(DEVICE_MEMORY_WHAT);
         mHandler.sendMessageDelayed(mHandler.obtainMessage(DEVICE_MEMORY_WHAT,
@@ -312,10 +314,10 @@
     * Constructor to run service. initializes the disk space threshold value
     * and posts an empty message to kickstart the process.
     */
-    public DeviceStorageMonitorService(Context context) {
+    @Override
+    public void onCreate(Context context) {
         mLastReportedFreeMemTime = 0;
-        mContext = context;
-        mResolver = mContext.getContentResolver();
+        mResolver = context.getContentResolver();
         //create StatFs object
         mDataFileStats = new StatFs(DATA_PATH.getAbsolutePath());
         mSystemFileStats = new StatFs(SYSTEM_PATH.getAbsolutePath());
@@ -331,9 +333,12 @@
         mStorageFullIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
         mStorageNotFullIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_NOT_FULL);
         mStorageNotFullIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+    }
 
+    @Override
+    public void onStart() {
         // cache storage thresholds
-        final StorageManager sm = StorageManager.from(context);
+        final StorageManager sm = StorageManager.from(getContext());
         mMemLowThreshold = sm.getStorageLowBytes(DATA_PATH);
         mMemFullThreshold = sm.getStorageFullBytes(DATA_PATH);
 
@@ -345,6 +350,78 @@
 
         mCacheFileDeletedObserver = new CacheFileDeletedObserver();
         mCacheFileDeletedObserver.startWatching();
+
+        publishBinderService(SERVICE, mRemoteService);
+        publishLocalService(DeviceStorageMonitorInternal.class, mLocalService);
+    }
+
+    private final DeviceStorageMonitorInternal mLocalService = new DeviceStorageMonitorInternal() {
+        @Override
+        public void checkMemory() {
+            // force an early check
+            postCheckMemoryMsg(true, 0);
+        }
+
+        @Override
+        public boolean isMemoryLow() {
+            return mLowMemFlag;
+        }
+
+        @Override
+        public long getMemoryLowThreshold() {
+            return mMemLowThreshold;
+        }
+    };
+
+    private final IBinder mRemoteService = new Binder() {
+        @Override
+        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                    != PackageManager.PERMISSION_GRANTED) {
+
+                pw.println("Permission Denial: can't dump " + SERVICE + " from from pid="
+                        + Binder.getCallingPid()
+                        + ", uid=" + Binder.getCallingUid());
+                return;
+            }
+
+            dumpImpl(pw);
+        }
+    };
+
+    void dumpImpl(PrintWriter pw) {
+        final Context context = getContext();
+
+        pw.println("Current DeviceStorageMonitor state:");
+
+        pw.print("  mFreeMem="); pw.print(Formatter.formatFileSize(context, mFreeMem));
+        pw.print(" mTotalMemory=");
+        pw.println(Formatter.formatFileSize(context, mTotalMemory));
+
+        pw.print("  mFreeMemAfterLastCacheClear=");
+        pw.println(Formatter.formatFileSize(context, mFreeMemAfterLastCacheClear));
+
+        pw.print("  mLastReportedFreeMem=");
+        pw.print(Formatter.formatFileSize(context, mLastReportedFreeMem));
+        pw.print(" mLastReportedFreeMemTime=");
+        TimeUtils.formatDuration(mLastReportedFreeMemTime, SystemClock.elapsedRealtime(), pw);
+        pw.println();
+
+        pw.print("  mLowMemFlag="); pw.print(mLowMemFlag);
+        pw.print(" mMemFullFlag="); pw.println(mMemFullFlag);
+
+        pw.print("  mClearSucceeded="); pw.print(mClearSucceeded);
+        pw.print(" mClearingCache="); pw.println(mClearingCache);
+
+        pw.print("  mMemLowThreshold=");
+        pw.print(Formatter.formatFileSize(context, mMemLowThreshold));
+        pw.print(" mMemFullThreshold=");
+        pw.println(Formatter.formatFileSize(context, mMemFullThreshold));
+
+        pw.print("  mMemCacheStartTrimThreshold=");
+        pw.print(Formatter.formatFileSize(context, mMemCacheStartTrimThreshold));
+        pw.print(" mMemCacheTrimToThreshold=");
+        pw.println(Formatter.formatFileSize(context, mMemCacheTrimToThreshold));
     }
 
     /**
@@ -352,7 +429,8 @@
     * an error dialog indicating low disk space and launch the Installer
     * application
     */
-    private final void sendNotification() {
+    private void sendNotification() {
+        final Context context = getContext();
         if(localLOGV) Slog.i(TAG, "Sending low memory notification");
         //log the event to event log with the amount of free storage(in bytes) left on the device
         EventLog.writeEvent(EventLogTags.LOW_STORAGE, mFreeMem);
@@ -363,86 +441,58 @@
         lowMemIntent.putExtra("memory", mFreeMem);
         lowMemIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         NotificationManager mNotificationMgr =
-                (NotificationManager)mContext.getSystemService(
+                (NotificationManager)context.getSystemService(
                         Context.NOTIFICATION_SERVICE);
-        CharSequence title = mContext.getText(
+        CharSequence title = context.getText(
                 com.android.internal.R.string.low_internal_storage_view_title);
-        CharSequence details = mContext.getText(
+        CharSequence details = context.getText(
                 com.android.internal.R.string.low_internal_storage_view_text);
-        PendingIntent intent = PendingIntent.getActivityAsUser(mContext, 0,  lowMemIntent, 0,
+        PendingIntent intent = PendingIntent.getActivityAsUser(context, 0,  lowMemIntent, 0,
                 null, UserHandle.CURRENT);
         Notification notification = new Notification();
         notification.icon = com.android.internal.R.drawable.stat_notify_disk_full;
         notification.tickerText = title;
         notification.flags |= Notification.FLAG_NO_CLEAR;
-        notification.setLatestEventInfo(mContext, title, details, intent);
+        notification.setLatestEventInfo(context, title, details, intent);
         mNotificationMgr.notifyAsUser(null, LOW_MEMORY_NOTIFICATION_ID, notification,
                 UserHandle.ALL);
-        mContext.sendStickyBroadcastAsUser(mStorageLowIntent, UserHandle.ALL);
+        context.sendStickyBroadcastAsUser(mStorageLowIntent, UserHandle.ALL);
     }
 
     /**
      * Cancels low storage notification and sends OK intent.
      */
-    private final void cancelNotification() {
+    private void cancelNotification() {
+        final Context context = getContext();
         if(localLOGV) Slog.i(TAG, "Canceling low memory notification");
         NotificationManager mNotificationMgr =
-                (NotificationManager)mContext.getSystemService(
+                (NotificationManager)context.getSystemService(
                         Context.NOTIFICATION_SERVICE);
         //cancel notification since memory has been freed
         mNotificationMgr.cancelAsUser(null, LOW_MEMORY_NOTIFICATION_ID, UserHandle.ALL);
 
-        mContext.removeStickyBroadcastAsUser(mStorageLowIntent, UserHandle.ALL);
-        mContext.sendBroadcastAsUser(mStorageOkIntent, UserHandle.ALL);
+        context.removeStickyBroadcastAsUser(mStorageLowIntent, UserHandle.ALL);
+        context.sendBroadcastAsUser(mStorageOkIntent, UserHandle.ALL);
     }
 
     /**
      * Send a notification when storage is full.
      */
-    private final void sendFullNotification() {
+    private void sendFullNotification() {
         if(localLOGV) Slog.i(TAG, "Sending memory full notification");
-        mContext.sendStickyBroadcastAsUser(mStorageFullIntent, UserHandle.ALL);
+        getContext().sendStickyBroadcastAsUser(mStorageFullIntent, UserHandle.ALL);
     }
 
     /**
      * Cancels memory full notification and sends "not full" intent.
      */
-    private final void cancelFullNotification() {
+    private void cancelFullNotification() {
         if(localLOGV) Slog.i(TAG, "Canceling memory full notification");
-        mContext.removeStickyBroadcastAsUser(mStorageFullIntent, UserHandle.ALL);
-        mContext.sendBroadcastAsUser(mStorageNotFullIntent, UserHandle.ALL);
+        getContext().removeStickyBroadcastAsUser(mStorageFullIntent, UserHandle.ALL);
+        getContext().sendBroadcastAsUser(mStorageNotFullIntent, UserHandle.ALL);
     }
 
-    public void updateMemory() {
-        int callingUid = getCallingUid();
-        if(callingUid != Process.SYSTEM_UID) {
-            return;
-        }
-        // force an early check
-        postCheckMemoryMsg(true, 0);
-    }
-
-    /**
-     * Callable from other things in the system service to obtain the low memory
-     * threshold.
-     * 
-     * @return low memory threshold in bytes
-     */
-    public long getMemoryLowThreshold() {
-        return mMemLowThreshold;
-    }
-
-    /**
-     * Callable from other things in the system process to check whether memory
-     * is low.
-     * 
-     * @return true is memory is low
-     */
-    public boolean isMemoryLow() {
-        return mLowMemFlag;
-    }
-
-    public static class CacheFileDeletedObserver extends FileObserver {
+    private static class CacheFileDeletedObserver extends FileObserver {
         public CacheFileDeletedObserver() {
             super(Environment.getDownloadCacheDirectory().getAbsolutePath(), FileObserver.DELETE);
         }
@@ -452,40 +502,4 @@
             EventLogTags.writeCacheFileDeleted(path);
         }
     }
-
-    @Override
-    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
-                != PackageManager.PERMISSION_GRANTED) {
-
-            pw.println("Permission Denial: can't dump " + SERVICE + " from from pid="
-                    + Binder.getCallingPid()
-                    + ", uid=" + Binder.getCallingUid());
-            return;
-        }
-
-        pw.println("Current DeviceStorageMonitor state:");
-        pw.print("  mFreeMem="); pw.print(Formatter.formatFileSize(mContext, mFreeMem));
-                pw.print(" mTotalMemory=");
-                pw.println(Formatter.formatFileSize(mContext, mTotalMemory));
-        pw.print("  mFreeMemAfterLastCacheClear=");
-                pw.println(Formatter.formatFileSize(mContext, mFreeMemAfterLastCacheClear));
-        pw.print("  mLastReportedFreeMem=");
-                pw.print(Formatter.formatFileSize(mContext, mLastReportedFreeMem));
-                pw.print(" mLastReportedFreeMemTime=");
-                TimeUtils.formatDuration(mLastReportedFreeMemTime, SystemClock.elapsedRealtime(), pw);
-                pw.println();
-        pw.print("  mLowMemFlag="); pw.print(mLowMemFlag);
-                pw.print(" mMemFullFlag="); pw.println(mMemFullFlag);
-        pw.print("  mClearSucceeded="); pw.print(mClearSucceeded);
-                pw.print(" mClearingCache="); pw.println(mClearingCache);
-        pw.print("  mMemLowThreshold=");
-                pw.print(Formatter.formatFileSize(mContext, mMemLowThreshold));
-                pw.print(" mMemFullThreshold=");
-                pw.println(Formatter.formatFileSize(mContext, mMemFullThreshold));
-        pw.print("  mMemCacheStartTrimThreshold=");
-                pw.print(Formatter.formatFileSize(mContext, mMemCacheStartTrimThreshold));
-                pw.print(" mMemCacheTrimToThreshold=");
-                pw.println(Formatter.formatFileSize(mContext, mMemCacheTrimToThreshold));
-    }
 }
diff --git a/services/core/java/com/android/server/twilight/TwilightListener.java b/services/core/java/com/android/server/twilight/TwilightListener.java
new file mode 100644
index 0000000..29ead44
--- /dev/null
+++ b/services/core/java/com/android/server/twilight/TwilightListener.java
@@ -0,0 +1,21 @@
+/*
+ * 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.twilight;
+
+public interface TwilightListener {
+    void onTwilightStateChanged();
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/twilight/TwilightManager.java b/services/core/java/com/android/server/twilight/TwilightManager.java
new file mode 100644
index 0000000..b3de58b
--- /dev/null
+++ b/services/core/java/com/android/server/twilight/TwilightManager.java
@@ -0,0 +1,24 @@
+/*
+ * 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.twilight;
+
+import android.os.Handler;
+
+public interface TwilightManager {
+    void registerListener(TwilightListener listener, Handler handler);
+    TwilightState getCurrentState();
+}
diff --git a/services/java/com/android/server/TwilightService.java b/services/core/java/com/android/server/twilight/TwilightService.java
similarity index 74%
rename from services/java/com/android/server/TwilightService.java
rename to services/core/java/com/android/server/twilight/TwilightService.java
index 0356faa..8feb97b 100644
--- a/services/java/com/android/server/TwilightService.java
+++ b/services/core/java/com/android/server/twilight/TwilightService.java
@@ -14,7 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.twilight;
+
+import com.android.server.SystemService;
+import com.android.server.TwilightCalculator;
 
 import android.app.AlarmManager;
 import android.app.PendingIntent;
@@ -34,9 +37,7 @@
 import android.text.format.Time;
 import android.util.Slog;
 
-import java.text.DateFormat;
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.Iterator;
 
 import libcore.util.Objects;
@@ -47,78 +48,88 @@
  * Used by the UI mode manager and other components to adjust night mode
  * effects based on sunrise and sunset.
  */
-public final class TwilightService {
-    private static final String TAG = "TwilightService";
-
-    private static final boolean DEBUG = false;
-
-    private static final String ACTION_UPDATE_TWILIGHT_STATE =
+public final class TwilightService extends SystemService {
+    static final String TAG = "TwilightService";
+    static final boolean DEBUG = false;
+    static final String ACTION_UPDATE_TWILIGHT_STATE =
             "com.android.server.action.UPDATE_TWILIGHT_STATE";
 
-    private final Context mContext;
-    private final AlarmManager mAlarmManager;
-    private final LocationManager mLocationManager;
-    private final LocationHandler mLocationHandler;
+    final Object mLock = new Object();
 
-    private final Object mLock = new Object();
+    AlarmManager mAlarmManager;
+    LocationManager mLocationManager;
+    LocationHandler mLocationHandler;
 
-    private final ArrayList<TwilightListenerRecord> mListeners =
+    final ArrayList<TwilightListenerRecord> mListeners =
             new ArrayList<TwilightListenerRecord>();
 
-    private boolean mSystemReady;
+    TwilightState mTwilightState;
 
-    private TwilightState mTwilightState;
-
-    public TwilightService(Context context) {
-        mContext = context;
-
-        mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
-        mLocationManager = (LocationManager)mContext.getSystemService(Context.LOCATION_SERVICE);
+    @Override
+    public void onStart() {
+        mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
+        mLocationManager = (LocationManager) getContext().getSystemService(
+                Context.LOCATION_SERVICE);
         mLocationHandler = new LocationHandler();
+
+        IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+        filter.addAction(Intent.ACTION_TIME_CHANGED);
+        filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+        filter.addAction(ACTION_UPDATE_TWILIGHT_STATE);
+        getContext().registerReceiver(mUpdateLocationReceiver, filter);
+
+        publishLocalService(TwilightManager.class, mService);
     }
 
-    void systemReady() {
-        synchronized (mLock) {
-            mSystemReady = true;
+    private static class TwilightListenerRecord implements Runnable {
+        private final TwilightListener mListener;
+        private final Handler mHandler;
 
-            IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-            filter.addAction(Intent.ACTION_TIME_CHANGED);
-            filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
-            filter.addAction(ACTION_UPDATE_TWILIGHT_STATE);
-            mContext.registerReceiver(mUpdateLocationReceiver, filter);
+        public TwilightListenerRecord(TwilightListener listener, Handler handler) {
+            mListener = listener;
+            mHandler = handler;
+        }
 
-            if (!mListeners.isEmpty()) {
-                mLocationHandler.enableLocationUpdates();
+        public void postUpdate() {
+            mHandler.post(this);
+        }
+
+        @Override
+        public void run() {
+            mListener.onTwilightStateChanged();
+        }
+
+    }
+
+    private final TwilightManager mService = new TwilightManager() {
+        /**
+         * Gets the current twilight state.
+         *
+         * @return The current twilight state, or null if no information is available.
+         */
+        @Override
+        public TwilightState getCurrentState() {
+            synchronized (mLock) {
+                return mTwilightState;
             }
         }
-    }
 
-    /**
-     * Gets the current twilight state.
-     *
-     * @return The current twilight state, or null if no information is available.
-     */
-    public TwilightState getCurrentState() {
-        synchronized (mLock) {
-            return mTwilightState;
-        }
-    }
+        /**
+         * Listens for twilight time.
+         *
+         * @param listener The listener.
+         */
+        @Override
+        public void registerListener(TwilightListener listener, Handler handler) {
+            synchronized (mLock) {
+                mListeners.add(new TwilightListenerRecord(listener, handler));
 
-    /**
-     * Listens for twilight time.
-     *
-     * @param listener The listener.
-     * @param handler The handler on which to post calls into the listener.
-     */
-    public void registerListener(TwilightListener listener, Handler handler) {
-        synchronized (mLock) {
-            mListeners.add(new TwilightListenerRecord(listener, handler));
-
-            if (mSystemReady && mListeners.size() == 1) {
-                mLocationHandler.enableLocationUpdates();
+                if (mListeners.size() == 1) {
+                    mLocationHandler.enableLocationUpdates();
+                }
             }
         }
-    }
+    };
 
     private void setTwilightState(TwilightState state) {
         synchronized (mLock) {
@@ -128,9 +139,10 @@
                 }
 
                 mTwilightState = state;
-                int count = mListeners.size();
-                for (int i = 0; i < count; i++) {
-                    mListeners.get(i).post();
+
+                final int listenerLen = mListeners.size();
+                for (int i = 0; i < listenerLen; i++) {
+                    mListeners.get(i).postUpdate();
                 }
             }
         }
@@ -162,124 +174,6 @@
         return distance >= totalAccuracy;
     }
 
-    /**
-     * Describes whether it is day or night.
-     * This object is immutable.
-     */
-    public static final class TwilightState {
-        private final boolean mIsNight;
-        private final long mYesterdaySunset;
-        private final long mTodaySunrise;
-        private final long mTodaySunset;
-        private final long mTomorrowSunrise;
-
-        TwilightState(boolean isNight,
-                long yesterdaySunset,
-                long todaySunrise, long todaySunset,
-                long tomorrowSunrise) {
-            mIsNight = isNight;
-            mYesterdaySunset = yesterdaySunset;
-            mTodaySunrise = todaySunrise;
-            mTodaySunset = todaySunset;
-            mTomorrowSunrise = tomorrowSunrise;
-        }
-
-        /**
-         * Returns true if it is currently night time.
-         */
-        public boolean isNight() {
-            return mIsNight;
-        }
-
-        /**
-         * Returns the time of yesterday's sunset in the System.currentTimeMillis() timebase,
-         * or -1 if the sun never sets.
-         */
-        public long getYesterdaySunset() {
-            return mYesterdaySunset;
-        }
-
-        /**
-         * Returns the time of today's sunrise in the System.currentTimeMillis() timebase,
-         * or -1 if the sun never rises.
-         */
-        public long getTodaySunrise() {
-            return mTodaySunrise;
-        }
-
-        /**
-         * Returns the time of today's sunset in the System.currentTimeMillis() timebase,
-         * or -1 if the sun never sets.
-         */
-        public long getTodaySunset() {
-            return mTodaySunset;
-        }
-
-        /**
-         * Returns the time of tomorrow's sunrise in the System.currentTimeMillis() timebase,
-         * or -1 if the sun never rises.
-         */
-        public long getTomorrowSunrise() {
-            return mTomorrowSunrise;
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            return o instanceof TwilightState && equals((TwilightState)o);
-        }
-
-        public boolean equals(TwilightState other) {
-            return other != null
-                    && mIsNight == other.mIsNight
-                    && mYesterdaySunset == other.mYesterdaySunset
-                    && mTodaySunrise == other.mTodaySunrise
-                    && mTodaySunset == other.mTodaySunset
-                    && mTomorrowSunrise == other.mTomorrowSunrise;
-        }
-
-        @Override
-        public int hashCode() {
-            return 0; // don't care
-        }
-
-        @Override
-        public String toString() {
-            DateFormat f = DateFormat.getDateTimeInstance();
-            return "{TwilightState: isNight=" + mIsNight
-                    + ", mYesterdaySunset=" + f.format(new Date(mYesterdaySunset))
-                    + ", mTodaySunrise=" + f.format(new Date(mTodaySunrise))
-                    + ", mTodaySunset=" + f.format(new Date(mTodaySunset))
-                    + ", mTomorrowSunrise=" + f.format(new Date(mTomorrowSunrise))
-                    + "}";
-        }
-    }
-
-    /**
-     * Listener for changes in twilight state.
-     */
-    public interface TwilightListener {
-        public void onTwilightStateChanged();
-    }
-
-    private static final class TwilightListenerRecord implements Runnable {
-        private final TwilightListener mListener;
-        private final Handler mHandler;
-
-        public TwilightListenerRecord(TwilightListener listener, Handler handler) {
-            mListener = listener;
-            mHandler = handler;
-        }
-
-        public void post() {
-            mHandler.post(this);
-        }
-
-        @Override
-        public void run() {
-            mListener.onTwilightStateChanged();
-        }
-    }
-
     private final class LocationHandler extends Handler {
         private static final int MSG_ENABLE_LOCATION_UPDATES = 1;
         private static final int MSG_GET_NEW_LOCATION_UPDATE = 2;
@@ -518,11 +412,12 @@
             }
 
             Intent updateIntent = new Intent(ACTION_UPDATE_TWILIGHT_STATE);
-            PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, updateIntent, 0);
+            PendingIntent pendingIntent = PendingIntent.getBroadcast(
+                    getContext(), 0, updateIntent, 0);
             mAlarmManager.cancel(pendingIntent);
             mAlarmManager.setExact(AlarmManager.RTC, nextUpdate, pendingIntent);
         }
-    };
+    }
 
     private final BroadcastReceiver mUpdateLocationReceiver = new BroadcastReceiver() {
         @Override
diff --git a/services/core/java/com/android/server/twilight/TwilightState.java b/services/core/java/com/android/server/twilight/TwilightState.java
new file mode 100644
index 0000000..91e24d7
--- /dev/null
+++ b/services/core/java/com/android/server/twilight/TwilightState.java
@@ -0,0 +1,112 @@
+/*
+ * 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.twilight;
+
+import java.text.DateFormat;
+import java.util.Date;
+
+/**
+ * Describes whether it is day or night.
+ * This object is immutable.
+ */
+public class TwilightState {
+    private final boolean mIsNight;
+    private final long mYesterdaySunset;
+    private final long mTodaySunrise;
+    private final long mTodaySunset;
+    private final long mTomorrowSunrise;
+
+    TwilightState(boolean isNight,
+            long yesterdaySunset,
+            long todaySunrise, long todaySunset,
+            long tomorrowSunrise) {
+        mIsNight = isNight;
+        mYesterdaySunset = yesterdaySunset;
+        mTodaySunrise = todaySunrise;
+        mTodaySunset = todaySunset;
+        mTomorrowSunrise = tomorrowSunrise;
+    }
+
+    /**
+     * Returns true if it is currently night time.
+     */
+    public boolean isNight() {
+        return mIsNight;
+    }
+
+    /**
+     * Returns the time of yesterday's sunset in the System.currentTimeMillis() timebase,
+     * or -1 if the sun never sets.
+     */
+    public long getYesterdaySunset() {
+        return mYesterdaySunset;
+    }
+
+    /**
+     * Returns the time of today's sunrise in the System.currentTimeMillis() timebase,
+     * or -1 if the sun never rises.
+     */
+    public long getTodaySunrise() {
+        return mTodaySunrise;
+    }
+
+    /**
+     * Returns the time of today's sunset in the System.currentTimeMillis() timebase,
+     * or -1 if the sun never sets.
+     */
+    public long getTodaySunset() {
+        return mTodaySunset;
+    }
+
+    /**
+     * Returns the time of tomorrow's sunrise in the System.currentTimeMillis() timebase,
+     * or -1 if the sun never rises.
+     */
+    public long getTomorrowSunrise() {
+        return mTomorrowSunrise;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        return o instanceof TwilightState && equals((TwilightState)o);
+    }
+
+    public boolean equals(TwilightState other) {
+        return other != null
+                && mIsNight == other.mIsNight
+                && mYesterdaySunset == other.mYesterdaySunset
+                && mTodaySunrise == other.mTodaySunrise
+                && mTodaySunset == other.mTodaySunset
+                && mTomorrowSunrise == other.mTomorrowSunrise;
+    }
+
+    @Override
+    public int hashCode() {
+        return 0; // don't care
+    }
+
+    @Override
+    public String toString() {
+        DateFormat f = DateFormat.getDateTimeInstance();
+        return "{TwilightState: isNight=" + mIsNight
+                + ", mYesterdaySunset=" + f.format(new Date(mYesterdaySunset))
+                + ", mTodaySunrise=" + f.format(new Date(mTodaySunrise))
+                + ", mTodaySunset=" + f.format(new Date(mTodaySunset))
+                + ", mTomorrowSunrise=" + f.format(new Date(mTomorrowSunrise))
+                + "}";
+    }
+}
diff --git a/services/java/com/android/server/updates/CarrierProvisioningUrlsInstallReceiver.java b/services/core/java/com/android/server/updates/CarrierProvisioningUrlsInstallReceiver.java
similarity index 100%
rename from services/java/com/android/server/updates/CarrierProvisioningUrlsInstallReceiver.java
rename to services/core/java/com/android/server/updates/CarrierProvisioningUrlsInstallReceiver.java
diff --git a/services/java/com/android/server/updates/CertPinInstallReceiver.java b/services/core/java/com/android/server/updates/CertPinInstallReceiver.java
similarity index 100%
rename from services/java/com/android/server/updates/CertPinInstallReceiver.java
rename to services/core/java/com/android/server/updates/CertPinInstallReceiver.java
diff --git a/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java b/services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
similarity index 100%
rename from services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
rename to services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
diff --git a/services/java/com/android/server/updates/IntentFirewallInstallReceiver.java b/services/core/java/com/android/server/updates/IntentFirewallInstallReceiver.java
similarity index 100%
rename from services/java/com/android/server/updates/IntentFirewallInstallReceiver.java
rename to services/core/java/com/android/server/updates/IntentFirewallInstallReceiver.java
diff --git a/services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java b/services/core/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
similarity index 100%
rename from services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
rename to services/core/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
diff --git a/services/java/com/android/server/updates/SmsShortCodesInstallReceiver.java b/services/core/java/com/android/server/updates/SmsShortCodesInstallReceiver.java
similarity index 100%
rename from services/java/com/android/server/updates/SmsShortCodesInstallReceiver.java
rename to services/core/java/com/android/server/updates/SmsShortCodesInstallReceiver.java
diff --git a/services/java/com/android/server/updates/TZInfoInstallReceiver.java b/services/core/java/com/android/server/updates/TZInfoInstallReceiver.java
similarity index 100%
rename from services/java/com/android/server/updates/TZInfoInstallReceiver.java
rename to services/core/java/com/android/server/updates/TZInfoInstallReceiver.java
diff --git a/services/java/com/android/server/usb/UsbDebuggingManager.java b/services/core/java/com/android/server/usb/UsbDebuggingManager.java
similarity index 100%
rename from services/java/com/android/server/usb/UsbDebuggingManager.java
rename to services/core/java/com/android/server/usb/UsbDebuggingManager.java
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/core/java/com/android/server/usb/UsbDeviceManager.java
similarity index 100%
rename from services/java/com/android/server/usb/UsbDeviceManager.java
rename to services/core/java/com/android/server/usb/UsbDeviceManager.java
diff --git a/services/java/com/android/server/usb/UsbHostManager.java b/services/core/java/com/android/server/usb/UsbHostManager.java
similarity index 100%
rename from services/java/com/android/server/usb/UsbHostManager.java
rename to services/core/java/com/android/server/usb/UsbHostManager.java
diff --git a/services/java/com/android/server/usb/UsbService.java b/services/core/java/com/android/server/usb/UsbService.java
similarity index 100%
rename from services/java/com/android/server/usb/UsbService.java
rename to services/core/java/com/android/server/usb/UsbService.java
diff --git a/services/java/com/android/server/usb/UsbSettingsManager.java b/services/core/java/com/android/server/usb/UsbSettingsManager.java
similarity index 100%
rename from services/java/com/android/server/usb/UsbSettingsManager.java
rename to services/core/java/com/android/server/usb/UsbSettingsManager.java
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
similarity index 98%
rename from services/java/com/android/server/WallpaperManagerService.java
rename to services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index e6b6b93..97ea52c 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.wallpaper;
 
 import static android.os.ParcelFileDescriptor.*;
 
@@ -85,8 +85,8 @@
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.JournaledFile;
 
-class WallpaperManagerService extends IWallpaperManager.Stub {
-    static final String TAG = "WallpaperService";
+public class WallpaperManagerService extends IWallpaperManager.Stub {
+    static final String TAG = "WallpaperManagerService";
     static final boolean DEBUG = false;
 
     final Object mLock = new Object[0];
@@ -98,7 +98,6 @@
     static final long MIN_WALLPAPER_CRASH_TIME = 10000;
     static final String WALLPAPER = "wallpaper";
     static final String WALLPAPER_INFO = "wallpaper_info.xml";
-
     /**
      * Name of the component used to display bitmap wallpapers from either the gallery or
      * built-in wallpapers.
@@ -505,7 +504,12 @@
         }
     }
 
-    String getName() {
+    /** Called by SystemBackupAgent */
+    public String getName() {
+        // Verify caller is the system
+        if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
+            throw new RuntimeException("getName() can only be called from the system process");
+        }
         synchronized (mLock) {
             return mWallpaperMap.get(0).name;
         }
@@ -1175,7 +1179,11 @@
     }
 
     // Called by SystemBackupAgent after files are restored to disk.
-    void settingsRestored() {
+    public void settingsRestored() {
+        // Verify caller is the system
+        if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
+            throw new RuntimeException("settingsRestored() can only be called from the system process");
+        }
         // TODO: If necessary, make it work for secondary users as well. This currently assumes
         // restores only to the primary user
         if (DEBUG) Slog.v(TAG, "settingsRestored");
diff --git a/services/java/com/android/server/wifi/README.txt b/services/core/java/com/android/server/wifi/README.txt
similarity index 100%
rename from services/java/com/android/server/wifi/README.txt
rename to services/core/java/com/android/server/wifi/README.txt
diff --git a/services/java/com/android/server/wifi/WifiController.java b/services/core/java/com/android/server/wifi/WifiController.java
similarity index 100%
rename from services/java/com/android/server/wifi/WifiController.java
rename to services/core/java/com/android/server/wifi/WifiController.java
diff --git a/services/java/com/android/server/wifi/WifiNotificationController.java b/services/core/java/com/android/server/wifi/WifiNotificationController.java
similarity index 100%
rename from services/java/com/android/server/wifi/WifiNotificationController.java
rename to services/core/java/com/android/server/wifi/WifiNotificationController.java
diff --git a/services/java/com/android/server/wifi/WifiService.java b/services/core/java/com/android/server/wifi/WifiService.java
similarity index 100%
rename from services/java/com/android/server/wifi/WifiService.java
rename to services/core/java/com/android/server/wifi/WifiService.java
diff --git a/services/java/com/android/server/wifi/WifiSettingsStore.java b/services/core/java/com/android/server/wifi/WifiSettingsStore.java
similarity index 100%
rename from services/java/com/android/server/wifi/WifiSettingsStore.java
rename to services/core/java/com/android/server/wifi/WifiSettingsStore.java
diff --git a/services/java/com/android/server/wifi/WifiTrafficPoller.java b/services/core/java/com/android/server/wifi/WifiTrafficPoller.java
similarity index 100%
rename from services/java/com/android/server/wifi/WifiTrafficPoller.java
rename to services/core/java/com/android/server/wifi/WifiTrafficPoller.java
diff --git a/services/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
similarity index 100%
rename from services/java/com/android/server/wm/AppTransition.java
rename to services/core/java/com/android/server/wm/AppTransition.java
diff --git a/services/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
similarity index 100%
rename from services/java/com/android/server/wm/AppWindowAnimator.java
rename to services/core/java/com/android/server/wm/AppWindowAnimator.java
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
similarity index 100%
rename from services/java/com/android/server/wm/AppWindowToken.java
rename to services/core/java/com/android/server/wm/AppWindowToken.java
diff --git a/services/java/com/android/server/wm/BlackFrame.java b/services/core/java/com/android/server/wm/BlackFrame.java
similarity index 100%
rename from services/java/com/android/server/wm/BlackFrame.java
rename to services/core/java/com/android/server/wm/BlackFrame.java
diff --git a/services/java/com/android/server/wm/DimLayer.java b/services/core/java/com/android/server/wm/DimLayer.java
similarity index 99%
rename from services/java/com/android/server/wm/DimLayer.java
rename to services/core/java/com/android/server/wm/DimLayer.java
index c189ddd..978d5b7 100644
--- a/services/java/com/android/server/wm/DimLayer.java
+++ b/services/core/java/com/android/server/wm/DimLayer.java
@@ -166,7 +166,7 @@
 
         final int dw, dh;
         final float xPos, yPos;
-        if (mStack.hasSibling()) {
+        if (!mStack.isFullscreen()) {
             dw = mBounds.width();
             dh = mBounds.height();
             xPos = mBounds.left;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
new file mode 100644
index 0000000..4064377
--- /dev/null
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -0,0 +1,433 @@
+/*
+ * 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.wm;
+
+import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
+import static com.android.server.wm.WindowManagerService.DEBUG_STACK;
+import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
+import static com.android.server.wm.WindowManagerService.TAG;
+
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.util.EventLog;
+import android.util.Slog;
+import android.view.Display;
+import android.view.DisplayInfo;
+import android.view.Surface;
+import com.android.server.EventLogTags;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+class DisplayContentList extends ArrayList<DisplayContent> {
+}
+
+/**
+ * Utility class for keeping track of the WindowStates and other pertinent contents of a
+ * particular Display.
+ *
+ * IMPORTANT: No method from this class should ever be used without holding
+ * WindowManagerService.mWindowMap.
+ */
+class DisplayContent {
+
+    /** Unique identifier of this stack. */
+    private final int mDisplayId;
+
+    /** Z-ordered (bottom-most first) list of all Window objects. Assigned to an element
+     * from mDisplayWindows; */
+    private WindowList mWindows = new WindowList();
+
+    // This protects the following display size properties, so that
+    // getDisplaySize() doesn't need to acquire the global lock.  This is
+    // needed because the window manager sometimes needs to use ActivityThread
+    // while it has its global state locked (for example to load animation
+    // resources), but the ActivityThread also needs get the current display
+    // size sometimes when it has its package lock held.
+    //
+    // These will only be modified with both mWindowMap and mDisplaySizeLock
+    // held (in that order) so the window manager doesn't need to acquire this
+    // lock when needing these values in its normal operation.
+    final Object mDisplaySizeLock = new Object();
+    int mInitialDisplayWidth = 0;
+    int mInitialDisplayHeight = 0;
+    int mInitialDisplayDensity = 0;
+    int mBaseDisplayWidth = 0;
+    int mBaseDisplayHeight = 0;
+    int mBaseDisplayDensity = 0;
+    private final DisplayInfo mDisplayInfo = new DisplayInfo();
+    private final Display mDisplay;
+
+    Rect mBaseDisplayRect = new Rect();
+    Rect mContentRect = new Rect();
+
+    // Accessed directly by all users.
+    boolean layoutNeeded;
+    int pendingLayoutChanges;
+    final boolean isDefaultDisplay;
+
+    /**
+     * Window tokens that are in the process of exiting, but still
+     * on screen for animations.
+     */
+    final ArrayList<WindowToken> mExitingTokens = new ArrayList<WindowToken>();
+
+    /**
+     * Application tokens that are in the process of exiting, but still
+     * on screen for animations.
+     */
+    final AppTokenList mExitingAppTokens = new AppTokenList();
+
+    /** Array containing all TaskStacks on this display.  Array
+     * is stored in display order with the current bottom stack at 0. */
+    private ArrayList<TaskStack> mStacks = new ArrayList<TaskStack>();
+
+    /** A special TaskStack with id==HOME_STACK_ID that moves to the bottom whenever any TaskStack
+     * (except a future lockscreen TaskStack) moves to the top. */
+    private TaskStack mHomeStack = null;
+
+    /** Detect user tapping outside of current focused stack bounds .*/
+    StackTapPointerEventListener mTapDetector;
+
+    /** Detect user tapping outside of current focused stack bounds .*/
+    Region mTouchExcludeRegion = new Region();
+
+    /** Save allocating when retrieving tasks */
+    private ArrayList<Task> mTaskHistory = new ArrayList<Task>();
+
+    /** Save allocating when calculating rects */
+    Rect mTmpRect = new Rect();
+
+    final WindowManagerService mService;
+
+    /**
+     * @param display May not be null.
+     * @param service TODO(cmautner):
+     */
+    DisplayContent(Display display, WindowManagerService service) {
+        mDisplay = display;
+        mDisplayId = display.getDisplayId();
+        display.getDisplayInfo(mDisplayInfo);
+        isDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;
+        mService = service;
+    }
+
+    int getDisplayId() {
+        return mDisplayId;
+    }
+
+    WindowList getWindowList() {
+        return mWindows;
+    }
+
+    Display getDisplay() {
+        return mDisplay;
+    }
+
+    DisplayInfo getDisplayInfo() {
+        return mDisplayInfo;
+    }
+
+    /**
+     * Returns true if the specified UID has access to this display.
+     */
+    public boolean hasAccess(int uid) {
+        return mDisplay.hasAccess(uid);
+    }
+
+    public boolean isPrivate() {
+        return (mDisplay.getFlags() & Display.FLAG_PRIVATE) != 0;
+    }
+
+    /**
+     * Retrieve the tasks on this display in stack order from the bottommost TaskStack up.
+     * @return All the Tasks, in order, on this display.
+     */
+    ArrayList<Task> getTasks() {
+        return mTaskHistory;
+    }
+
+    void addTask(Task task, boolean toTop) {
+        mTaskHistory.remove(task);
+
+        final int userId = task.mUserId;
+        int taskNdx;
+        final int numTasks = mTaskHistory.size();
+        if (toTop) {
+            for (taskNdx = numTasks - 1; taskNdx >= 0; --taskNdx) {
+                if (mTaskHistory.get(taskNdx).mUserId == userId) {
+                    break;
+                }
+            }
+            ++taskNdx;
+        } else {
+            for (taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
+                if (mTaskHistory.get(taskNdx).mUserId == userId) {
+                    break;
+                }
+            }
+        }
+
+        mTaskHistory.add(taskNdx, task);
+        EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.taskId, toTop ? 1 : 0, taskNdx);
+    }
+
+    void removeTask(Task task) {
+        mTaskHistory.remove(task);
+    }
+
+    TaskStack getHomeStack() {
+        return mHomeStack;
+    }
+
+    void updateDisplayInfo() {
+        // Save old size.
+        int oldWidth = mDisplayInfo.logicalWidth;
+        int oldHeight = mDisplayInfo.logicalHeight;
+        mDisplay.getDisplayInfo(mDisplayInfo);
+
+        for (int i = mStacks.size() - 1; i >= 0; --i) {
+            final TaskStack stack = mStacks.get(i);
+            if (!stack.isFullscreen()) {
+                stack.resizeBounds(oldWidth, oldHeight, mDisplayInfo.logicalWidth,
+                        mDisplayInfo.logicalHeight);
+            }
+        }
+    }
+
+    void getLogicalDisplayRect(Rect out) {
+        updateDisplayInfo();
+        // Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked.
+        final int orientation = mDisplayInfo.rotation;
+        boolean rotated = (orientation == Surface.ROTATION_90
+                || orientation == Surface.ROTATION_270);
+        final int physWidth = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
+        final int physHeight = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
+        int width = mDisplayInfo.logicalWidth;
+        int left = (physWidth - width) / 2;
+        int height = mDisplayInfo.logicalHeight;
+        int top = (physHeight - height) / 2;
+        out.set(left, top, left + width, top + height);
+    }
+
+    /** @return The number of tokens in all of the Tasks on this display. */
+    int numTokens() {
+        int count = 0;
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            count += mTaskHistory.get(taskNdx).mAppTokens.size();
+        }
+        return count;
+    }
+
+    /** Refer to {@link WindowManagerService#createStack(int, int)} */
+    TaskStack createStack(int stackId) {
+        if (DEBUG_STACK) Slog.d(TAG, "createStack: stackId=" + stackId);
+        TaskStack newStack = new TaskStack(mService, stackId, this);
+        if (stackId == HOME_STACK_ID) {
+            if (mHomeStack != null) {
+                throw new IllegalArgumentException("createStack: HOME_STACK_ID (0) not first.");
+            }
+            mHomeStack = newStack;
+        }
+        mStacks.add(newStack);
+        layoutNeeded = true;
+        return newStack;
+    }
+
+    void moveStack(TaskStack stack, boolean toTop) {
+        mStacks.remove(stack);
+        mStacks.add(toTop ? mStacks.size() : 0, stack);
+    }
+
+    TaskStack removeStack(TaskStack stack) {
+        mStacks.remove(stack);
+        if (!mStacks.isEmpty()) {
+            return mStacks.get(mStacks.size() - 1);
+        }
+        return null;
+    }
+
+    /**
+     * Propagate the new bounds to all child stacks.
+     * @param contentRect The bounds to apply at the top level.
+     */
+    void resize(Rect contentRect) {
+        mContentRect.set(contentRect);
+    }
+
+    boolean getStackBounds(int stackId, Rect bounds) {
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final TaskStack stack = mStacks.get(stackNdx);
+            if (stackId == stack.mStackId) {
+                bounds.set(stack.mBounds);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    int stackIdFromPoint(int x, int y) {
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final TaskStack stack = mStacks.get(stackNdx);
+            stack.getBounds(mTmpRect);
+            if (mTmpRect.contains(x, y)) {
+                return stack.mStackId;
+            }
+        }
+        return -1;
+    }
+
+    void setTouchExcludeRegion(TaskStack focusedStack) {
+        mTouchExcludeRegion.set(mBaseDisplayRect);
+        WindowList windows = getWindowList();
+        for (int i = windows.size() - 1; i >= 0; --i) {
+            final WindowState win = windows.get(i);
+            final TaskStack stack = win.getStack();
+            if (win.isVisibleLw() && stack != null && stack != focusedStack) {
+                mTmpRect.set(win.mVisibleFrame);
+                mTmpRect.intersect(win.mVisibleInsets);
+                mTouchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE);
+            }
+        }
+    }
+
+    void switchUserStacks(int oldUserId, int newUserId) {
+        final WindowList windows = getWindowList();
+        for (int i = 0; i < windows.size(); i++) {
+            final WindowState win = windows.get(i);
+            if (win.isHiddenFromUserLocked()) {
+                if (DEBUG_VISIBILITY) Slog.w(TAG, "user changing " + newUserId + " hiding "
+                        + win + ", attrs=" + win.mAttrs.type + ", belonging to "
+                        + win.mOwnerUid);
+                win.hideLw(false);
+            }
+        }
+
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            mStacks.get(stackNdx).switchUser(newUserId);
+        }
+    }
+
+    void resetAnimationBackgroundAnimator() {
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            mStacks.get(stackNdx).resetAnimationBackgroundAnimator();
+        }
+    }
+
+    boolean animateDimLayers() {
+        boolean result = false;
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            result |= mStacks.get(stackNdx).animateDimLayers();
+        }
+        return result;
+    }
+
+    void resetDimming() {
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            mStacks.get(stackNdx).resetDimmingTag();
+        }
+    }
+
+    boolean isDimming() {
+        boolean result = false;
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            result |= mStacks.get(stackNdx).isDimming();
+        }
+        return result;
+    }
+
+    void stopDimmingIfNeeded() {
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            mStacks.get(stackNdx).stopDimmingIfNeeded();
+        }
+    }
+
+    void close() {
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            mStacks.get(stackNdx).close();
+        }
+    }
+
+    public void dump(String prefix, PrintWriter pw) {
+        pw.print(prefix); pw.print("Display: mDisplayId="); pw.println(mDisplayId);
+        final String subPrefix = "  " + prefix;
+        pw.print(subPrefix); pw.print("init="); pw.print(mInitialDisplayWidth); pw.print("x");
+            pw.print(mInitialDisplayHeight); pw.print(" "); pw.print(mInitialDisplayDensity);
+            pw.print("dpi");
+            if (mInitialDisplayWidth != mBaseDisplayWidth
+                    || mInitialDisplayHeight != mBaseDisplayHeight
+                    || mInitialDisplayDensity != mBaseDisplayDensity) {
+                pw.print(" base=");
+                pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight);
+                pw.print(" "); pw.print(mBaseDisplayDensity); pw.print("dpi");
+            }
+            pw.print(" cur=");
+            pw.print(mDisplayInfo.logicalWidth);
+            pw.print("x"); pw.print(mDisplayInfo.logicalHeight);
+            pw.print(" app=");
+            pw.print(mDisplayInfo.appWidth);
+            pw.print("x"); pw.print(mDisplayInfo.appHeight);
+            pw.print(" rng="); pw.print(mDisplayInfo.smallestNominalAppWidth);
+            pw.print("x"); pw.print(mDisplayInfo.smallestNominalAppHeight);
+            pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth);
+            pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
+            pw.print(subPrefix); pw.print("layoutNeeded="); pw.println(layoutNeeded);
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final TaskStack stack = mStacks.get(stackNdx);
+            pw.print(prefix); pw.print("mStacks[" + stackNdx + "]"); pw.println(stack.mStackId);
+            stack.dump(prefix + "  ", pw);
+        }
+        int ndx = numTokens();
+        if (ndx > 0) {
+            pw.println();
+            pw.println("  Application tokens in Z order:");
+            getTasks();
+            for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+                AppTokenList tokens = mTaskHistory.get(taskNdx).mAppTokens;
+                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+                    final AppWindowToken wtoken = tokens.get(tokenNdx);
+                    pw.print("  App #"); pw.print(ndx--);
+                            pw.print(' '); pw.print(wtoken); pw.println(":");
+                    wtoken.dump(pw, "    ");
+                }
+            }
+        }
+        if (mExitingTokens.size() > 0) {
+            pw.println();
+            pw.println("  Exiting tokens:");
+            for (int i=mExitingTokens.size()-1; i>=0; i--) {
+                WindowToken token = mExitingTokens.get(i);
+                pw.print("  Exiting #"); pw.print(i);
+                pw.print(' '); pw.print(token);
+                pw.println(':');
+                token.dump(pw, "    ");
+            }
+        }
+        if (mExitingAppTokens.size() > 0) {
+            pw.println();
+            pw.println("  Exiting application tokens:");
+            for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
+                WindowToken token = mExitingAppTokens.get(i);
+                pw.print("  Exiting App #"); pw.print(i);
+                  pw.print(' '); pw.print(token);
+                  pw.println(':');
+                  token.dump(pw, "    ");
+            }
+        }
+        pw.println();
+    }
+}
diff --git a/services/java/com/android/server/wm/DisplayMagnifier.java b/services/core/java/com/android/server/wm/DisplayMagnifier.java
similarity index 100%
rename from services/java/com/android/server/wm/DisplayMagnifier.java
rename to services/core/java/com/android/server/wm/DisplayMagnifier.java
diff --git a/services/java/com/android/server/wm/DisplaySettings.java b/services/core/java/com/android/server/wm/DisplaySettings.java
similarity index 100%
rename from services/java/com/android/server/wm/DisplaySettings.java
rename to services/core/java/com/android/server/wm/DisplaySettings.java
diff --git a/services/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
similarity index 100%
rename from services/java/com/android/server/wm/DragState.java
rename to services/core/java/com/android/server/wm/DragState.java
diff --git a/services/java/com/android/server/wm/FakeWindowImpl.java b/services/core/java/com/android/server/wm/FakeWindowImpl.java
similarity index 100%
rename from services/java/com/android/server/wm/FakeWindowImpl.java
rename to services/core/java/com/android/server/wm/FakeWindowImpl.java
diff --git a/services/java/com/android/server/wm/FocusedStackFrame.java b/services/core/java/com/android/server/wm/FocusedStackFrame.java
similarity index 97%
rename from services/java/com/android/server/wm/FocusedStackFrame.java
rename to services/core/java/com/android/server/wm/FocusedStackFrame.java
index cc48b86..f1f5fe8 100644
--- a/services/java/com/android/server/wm/FocusedStackFrame.java
+++ b/services/core/java/com/android/server/wm/FocusedStackFrame.java
@@ -41,7 +41,7 @@
     private final SurfaceControl mSurfaceControl;
     private final Surface mSurface = new Surface();
     private final Rect mLastBounds = new Rect();
-    private final Rect mBounds = new Rect();
+    final Rect mBounds = new Rect();
     private final Rect mTmpDrawRect = new Rect();
 
     public FocusedStackFrame(Display display, SurfaceSession session) {
@@ -131,9 +131,9 @@
         }
     }
 
-    public void setBounds(Rect bounds) {
-        if (false && DEBUG_STACK) Slog.i(TAG, "setBounds: bounds=" + bounds);
-        mBounds.set(bounds);
+    public void setBounds(TaskStack stack) {
+        stack.getBounds(mBounds);
+        if (false && DEBUG_STACK) Slog.i(TAG, "setBounds: bounds=" + mBounds);
     }
 
     public void setLayer(int layer) {
diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
similarity index 99%
rename from services/java/com/android/server/wm/InputMonitor.java
rename to services/core/java/com/android/server/wm/InputMonitor.java
index 3d2ec45..803b9ac 100644
--- a/services/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -58,6 +58,8 @@
     private final Object mInputDevicesReadyMonitor = new Object();
     private boolean mInputDevicesReady;
 
+    Rect mTmpRect = new Rect();
+
     public InputMonitor(WindowManagerService service) {
         mService = service;
     }
@@ -175,7 +177,8 @@
         if (modal && child.mAppToken != null) {
             // Limit the outer touch to the activity stack region.
             flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-            inputWindowHandle.touchableRegion.set(child.getStackBounds());
+            child.getStackBounds(mTmpRect);
+            inputWindowHandle.touchableRegion.set(mTmpRect);
         } else {
             // Not modal or full screen modal
             child.getTouchableRegion(inputWindowHandle.touchableRegion);
diff --git a/services/java/com/android/server/wm/KeyguardDisableHandler.java b/services/core/java/com/android/server/wm/KeyguardDisableHandler.java
similarity index 100%
rename from services/java/com/android/server/wm/KeyguardDisableHandler.java
rename to services/core/java/com/android/server/wm/KeyguardDisableHandler.java
diff --git a/services/java/com/android/server/wm/PointerEventDispatcher.java b/services/core/java/com/android/server/wm/PointerEventDispatcher.java
similarity index 100%
rename from services/java/com/android/server/wm/PointerEventDispatcher.java
rename to services/core/java/com/android/server/wm/PointerEventDispatcher.java
diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
similarity index 100%
rename from services/java/com/android/server/wm/ScreenRotationAnimation.java
rename to services/core/java/com/android/server/wm/ScreenRotationAnimation.java
diff --git a/services/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
similarity index 100%
rename from services/java/com/android/server/wm/Session.java
rename to services/core/java/com/android/server/wm/Session.java
diff --git a/services/java/com/android/server/wm/StackTapPointerEventListener.java b/services/core/java/com/android/server/wm/StackTapPointerEventListener.java
similarity index 100%
rename from services/java/com/android/server/wm/StackTapPointerEventListener.java
rename to services/core/java/com/android/server/wm/StackTapPointerEventListener.java
diff --git a/services/java/com/android/server/wm/StartingData.java b/services/core/java/com/android/server/wm/StartingData.java
similarity index 100%
rename from services/java/com/android/server/wm/StartingData.java
rename to services/core/java/com/android/server/wm/StartingData.java
diff --git a/services/java/com/android/server/wm/StrictModeFlash.java b/services/core/java/com/android/server/wm/StrictModeFlash.java
similarity index 100%
rename from services/java/com/android/server/wm/StrictModeFlash.java
rename to services/core/java/com/android/server/wm/StrictModeFlash.java
diff --git a/services/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
similarity index 100%
rename from services/java/com/android/server/wm/Task.java
rename to services/core/java/com/android/server/wm/Task.java
diff --git a/services/java/com/android/server/wm/TaskGroup.java b/services/core/java/com/android/server/wm/TaskGroup.java
similarity index 100%
rename from services/java/com/android/server/wm/TaskGroup.java
rename to services/core/java/com/android/server/wm/TaskGroup.java
diff --git a/services/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
similarity index 83%
rename from services/java/com/android/server/wm/TaskStack.java
rename to services/core/java/com/android/server/wm/TaskStack.java
index cb29df4..ef245f9 100644
--- a/services/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -26,8 +26,6 @@
 import android.util.TypedValue;
 import com.android.server.EventLogTags;
 
-import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
-
 import java.io.PrintWriter;
 import java.util.ArrayList;
 
@@ -49,8 +47,9 @@
      * mTaskHistory in the ActivityStack with the same mStackId */
     private final ArrayList<Task> mTasks = new ArrayList<Task>();
 
-    /** The StackBox this sits in. */
-    StackBox mStackBox;
+    /** Content limits relative to the DisplayContent this sits in. Empty indicates fullscreen,
+     * Nonempty is size of this TaskStack but is also used to scale if DisplayContent changes. */
+    Rect mBounds = new Rect();
 
     /** Used to support {@link android.view.WindowManager.LayoutParams#FLAG_DIM_BEHIND} */
     final DimLayer mDimLayer;
@@ -74,6 +73,9 @@
         mDisplayContent = displayContent;
         mDimLayer = new DimLayer(service, this);
         mAnimationBackgroundSurface = new DimLayer(service, this);
+        // TODO: remove bounds from log, they are always 0.
+        EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId, mBounds.left, mBounds.top,
+                mBounds.right, mBounds.bottom);
     }
 
     DisplayContent getDisplayContent() {
@@ -84,12 +86,64 @@
         return mTasks;
     }
 
-    boolean isHomeStack() {
-        return mStackId == HOME_STACK_ID;
+    private void resizeWindows() {
+        final boolean underStatusBar = mBounds.top == 0;
+
+        final ArrayList<WindowState> resizingWindows = mService.mResizingWindows;
+        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
+            final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows;
+                for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+                    final WindowState win = windows.get(winNdx);
+                    if (!resizingWindows.contains(win)) {
+                        if (WindowManagerService.DEBUG_RESIZE) Slog.d(TAG,
+                                "setBounds: Resizing " + win);
+                        resizingWindows.add(win);
+                    }
+                    win.mUnderStatusBar = underStatusBar;
+                }
+            }
+        }
     }
 
-    boolean hasSibling() {
-        return mStackBox.mParent != null;
+    boolean setBounds(Rect bounds) {
+        if (mBounds.equals(bounds)) {
+            return false;
+        }
+
+        mDimLayer.setBounds(bounds);
+        mAnimationBackgroundSurface.setBounds(bounds);
+        mBounds.set(bounds);
+
+        resizeWindows();
+        return true;
+    }
+
+    void getBounds(Rect out) {
+        if (mBounds.isEmpty()) {
+            mDisplayContent.getLogicalDisplayRect(out);
+        } else {
+            out.set(mBounds);
+        }
+        out.intersect(mDisplayContent.mContentRect);
+    }
+
+    boolean isFullscreen() {
+        return mBounds.isEmpty();
+    }
+
+    void resizeBounds(float oldWidth, float oldHeight, float newWidth, float newHeight) {
+        if (oldWidth == newWidth && oldHeight == newHeight) {
+            return;
+        }
+        float widthScale = newWidth / oldWidth;
+        float heightScale = newHeight / oldHeight;
+        mBounds.left = (int)(mBounds.left * widthScale + 0.5);
+        mBounds.top = (int)(mBounds.top * heightScale + 0.5);
+        mBounds.right = (int)(mBounds.right * widthScale + 0.5);
+        mBounds.bottom = (int)(mBounds.bottom * heightScale + 0.5);
+        resizeWindows();
     }
 
     /**
@@ -97,9 +151,7 @@
      * @param task The task to add.
      * @param toTop Whether to add it to the top or bottom.
      */
-    boolean addTask(Task task, boolean toTop) {
-        mStackBox.makeDirty();
-
+    void addTask(Task task, boolean toTop) {
         int stackNdx;
         if (!toTop) {
             stackNdx = 0;
@@ -122,20 +174,20 @@
 
         task.mStack = this;
         mDisplayContent.addTask(task, toTop);
-        return mDisplayContent.moveHomeStackBox(mStackId == HOME_STACK_ID);
+        mDisplayContent.moveStack(this, true);
     }
 
-    boolean moveTaskToTop(Task task) {
+    void moveTaskToTop(Task task) {
         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "moveTaskToTop: task=" + task + " Callers="
                 + Debug.getCallers(6));
         mTasks.remove(task);
-        return addTask(task, true);
+        addTask(task, true);
     }
 
-    boolean moveTaskToBottom(Task task) {
+    void moveTaskToBottom(Task task) {
         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "moveTaskToBottom: task=" + task);
         mTasks.remove(task);
-        return addTask(task, false);
+        addTask(task, false);
     }
 
     /**
@@ -145,7 +197,6 @@
      */
     void removeTask(Task task) {
         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "removeTask: task=" + task);
-        mStackBox.makeDirty();
         mTasks.remove(task);
         mDisplayContent.removeTask(task);
     }
@@ -154,7 +205,11 @@
         mAnimationBackgroundSurface.destroySurface();
         mDimLayer.destroySurface();
         EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
-        return mStackBox.remove();
+        TaskStack next = mDisplayContent.removeStack(this);
+        if (next != null) {
+            return next.mStackId;
+        }
+        return -1;
     }
 
     void resetAnimationBackgroundAnimator() {
@@ -259,28 +314,6 @@
         }
     }
 
-    void setBounds(Rect bounds, boolean underStatusBar) {
-        mDimLayer.setBounds(bounds);
-        mAnimationBackgroundSurface.setBounds(bounds);
-
-        final ArrayList<WindowState> resizingWindows = mService.mResizingWindows;
-        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
-            final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens;
-            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
-                final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows;
-                for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
-                    final WindowState win = windows.get(winNdx);
-                    if (!resizingWindows.contains(win)) {
-                        if (WindowManagerService.DEBUG_RESIZE) Slog.d(TAG,
-                                "setBounds: Resizing " + win);
-                        resizingWindows.add(win);
-                    }
-                    win.mUnderStatusBar = underStatusBar;
-                }
-            }
-        }
-    }
-
     void switchUser(int userId) {
         int top = mTasks.size();
         for (int taskNdx = 0; taskNdx < top; ++taskNdx) {
@@ -293,6 +326,11 @@
         }
     }
 
+    void close() {
+        mDimLayer.mDimSurface.destroy();
+        mAnimationBackgroundSurface.mDimSurface.destroy();
+    }
+
     public void dump(String prefix, PrintWriter pw) {
         pw.print(prefix); pw.print("mStackId="); pw.println(mStackId);
         for (int taskNdx = 0; taskNdx < mTasks.size(); ++taskNdx) {
diff --git a/services/java/com/android/server/wm/ViewServer.java b/services/core/java/com/android/server/wm/ViewServer.java
similarity index 100%
rename from services/java/com/android/server/wm/ViewServer.java
rename to services/core/java/com/android/server/wm/ViewServer.java
diff --git a/services/java/com/android/server/wm/Watermark.java b/services/core/java/com/android/server/wm/Watermark.java
similarity index 100%
rename from services/java/com/android/server/wm/Watermark.java
rename to services/core/java/com/android/server/wm/Watermark.java
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
similarity index 100%
rename from services/java/com/android/server/wm/WindowAnimator.java
rename to services/core/java/com/android/server/wm/WindowAnimator.java
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
similarity index 98%
rename from services/java/com/android/server/wm/WindowManagerService.java
rename to services/core/java/com/android/server/wm/WindowManagerService.java
index f9773a6..04129e2 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -45,7 +45,6 @@
 import com.android.server.power.ShutdownThread;
 
 import android.Manifest;
-import android.app.ActivityManager.StackBoxInfo;
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
 import android.app.StatusBarManager;
@@ -293,8 +292,6 @@
 
     final private KeyguardDisableHandler mKeyguardDisableHandler;
 
-    private final boolean mHeadless;
-
     final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -734,7 +731,6 @@
                 com.android.internal.R.bool.config_sf_limitedAlpha);
         mInputManager = inputManager; // Must be before createDisplayContentLocked.
         mDisplayManagerService = displayManager;
-        mHeadless = displayManager.isHeadless();
         mDisplaySettings = new DisplaySettings(context);
         mDisplaySettings.readSettingsLocked();
 
@@ -3778,10 +3774,8 @@
             if (stack == null) {
                 mFocusedStackFrame.setVisibility(false);
             } else {
-                final StackBox box = stack.mStackBox;
-                final Rect bounds = box.mBounds;
-                final boolean multipleStacks = box.mParent != null;
-                mFocusedStackFrame.setBounds(bounds);
+                mFocusedStackFrame.setBounds(stack);
+                final boolean multipleStacks = !stack.isFullscreen();
                 mFocusedStackFrame.setVisibility(multipleStacks);
             }
         } finally {
@@ -4788,10 +4782,12 @@
                 }
                 final TaskStack stack = task.mStack;
                 final DisplayContent displayContent = task.getDisplayContent();
-                final boolean isHomeStackTask = stack.isHomeStack();
-                if (isHomeStackTask != displayContent.homeOnTop()) {
-                    // First move the stack itself.
-                    displayContent.moveHomeStackBox(isHomeStackTask);
+                displayContent.moveStack(stack, true);
+                final TaskStack homeStack = displayContent.getHomeStack();
+                if (homeStack != stack) {
+                    // When a non-home stack moves to the top, the home stack moves to the
+                    // bottom.
+                    displayContent.moveStack(homeStack, false);
                 }
                 stack.moveTaskToTop(task);
             }
@@ -4822,36 +4818,19 @@
     /**
      * Create a new TaskStack and place it next to an existing stack.
      * @param stackId The unique identifier of the new stack.
-     * @param relativeStackBoxId The existing stack that this stack goes before or after.
-     * @param position One of:
-     *      {@link StackBox#TASK_STACK_GOES_BEFORE}
-     *      {@link StackBox#TASK_STACK_GOES_AFTER}
-     *      {@link StackBox#TASK_STACK_GOES_ABOVE}
-     *      {@link StackBox#TASK_STACK_GOES_BELOW}
-     *      {@link StackBox#TASK_STACK_GOES_UNDER}
-     *      {@link StackBox#TASK_STACK_GOES_OVER}
-     * @param weight Relative weight for determining how big to make the new TaskStack.
      */
-    public void createStack(int stackId, int relativeStackBoxId, int position, float weight) {
+    public void createStack(int stackId, int displayId) {
         synchronized (mWindowMap) {
-            if (position <= StackBox.TASK_STACK_GOES_BELOW &&
-                    (weight < STACK_WEIGHT_MIN || weight > STACK_WEIGHT_MAX)) {
-                throw new IllegalArgumentException(
-                        "createStack: weight must be between " + STACK_WEIGHT_MIN + " and " +
-                        STACK_WEIGHT_MAX + ", weight=" + weight);
-            }
             final int numDisplays = mDisplayContents.size();
             for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
                 final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
-                TaskStack stack = displayContent.createStack(stackId, relativeStackBoxId, position,
-                        weight);
-                if (stack != null) {
+                if (displayContent.getDisplayId() == displayId) {
+                    TaskStack stack = displayContent.createStack(stackId);
                     mStackIdToStack.put(stackId, stack);
                     performLayoutAndPlaceSurfacesLocked();
                     return;
                 }
             }
-            Slog.e(TAG, "createStack: Unable to find relativeStackBoxId=" + relativeStackBoxId);
         }
     }
 
@@ -4863,7 +4842,9 @@
                 int nextStackId = stack.remove();
                 stack.getDisplayContent().layoutNeeded = true;
                 requestTraversalLocked();
-                return nextStackId;
+                if (nextStackId > HOME_STACK_ID) {
+                    return nextStackId;
+                }
             }
             if (DEBUG_STACK) Slog.i(TAG, "removeStack: could not find stackId=" + stackId);
         }
@@ -4898,40 +4879,27 @@
         }
     }
 
-    public void resizeStackBox(int stackBoxId, float weight) {
-        if (weight < STACK_WEIGHT_MIN || weight > STACK_WEIGHT_MAX) {
-            throw new IllegalArgumentException(
-                    "resizeStack: weight must be between " + STACK_WEIGHT_MIN + " and " +
-                    STACK_WEIGHT_MAX + ", weight=" + weight);
-        }
+    public void resizeStack(int stackId, Rect bounds) {
         synchronized (mWindowMap) {
-            final int numDisplays = mDisplayContents.size();
-            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-                if (mDisplayContents.valueAt(displayNdx).resizeStack(stackBoxId, weight)) {
-                    performLayoutAndPlaceSurfacesLocked();
-                    return;
-                }
+            final TaskStack stack = mStackIdToStack.get(stackId);
+            if (stack == null) {
+                throw new IllegalArgumentException("resizeStack: stackId " + stackId
+                        + " not found.");
             }
-        }
-        throw new IllegalArgumentException("resizeStack: stackBoxId " + stackBoxId
-                + " not found.");
-    }
-
-    public ArrayList<StackBoxInfo> getStackBoxInfos() {
-        synchronized(mWindowMap) {
-            return getDefaultDisplayContentLocked().getStackBoxInfos();
+            if (stack.setBounds(bounds)) {
+                stack.getDisplayContent().layoutNeeded = true;
+                performLayoutAndPlaceSurfacesLocked();
+            }
         }
     }
 
-    public Rect getStackBounds(int stackId) {
-        final int numDisplays = mDisplayContents.size();
-        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            Rect bounds = mDisplayContents.valueAt(displayNdx).getStackBounds(stackId);
-            if (bounds != null) {
-                return bounds;
-            }
+    public void getStackBounds(int stackId, Rect bounds) {
+        final TaskStack stack = mStackIdToStack.get(stackId);
+        if (stack != null) {
+            stack.getBounds(bounds);
+            return;
         }
-        return null;
+        bounds.setEmpty();
     }
 
     // -------------------------------------------------------------
@@ -5259,7 +5227,7 @@
 
     public void performBootTimeout() {
         synchronized(mWindowMap) {
-            if (mDisplayEnabled || mHeadless) {
+            if (mDisplayEnabled) {
                 return;
             }
             Slog.w(TAG, "***** BOOT TIMEOUT: forcing display enabled");
@@ -5443,7 +5411,6 @@
     // only allow disables from pids which have count on, etc.
     @Override
     public void showStrictModeViolation(boolean on) {
-        if (mHeadless) return;
         int pid = Binder.getCallingPid();
         mH.sendMessage(mH.obtainMessage(H.SHOW_STRICT_MODE_VIOLATION, on ? 1 : 0, pid));
     }
@@ -5589,7 +5556,7 @@
                                 continue;
                             }
                             appWin = ws;
-                            stackBounds.set(ws.getStackBounds());
+                            ws.getStackBounds(stackBounds);
                         }
                     }
 
@@ -8218,7 +8185,7 @@
         }
 
         mPolicy.getContentRectLw(mTmpContentRect);
-        displayContent.setStackBoxSize(mTmpContentRect);
+        displayContent.resize(mTmpContentRect);
 
         int seq = mLayoutSeq+1;
         if (seq < 0) seq = 0;
@@ -8813,7 +8780,8 @@
             if (canBeSeen) {
                 // This function assumes that the contents of the default display are
                 // processed first before secondary displays.
-                if (w.mDisplayContent.isDefaultDisplay) {
+                final DisplayContent displayContent = w.mDisplayContent;
+                if (displayContent.isDefaultDisplay) {
                     // While a dream or keyguard is showing, obscure ordinary application
                     // content on secondary displays (by forcibly enabling mirroring unless
                     // there is other content we want to show) but still allow opaque
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
similarity index 99%
rename from services/java/com/android/server/wm/WindowState.java
rename to services/core/java/com/android/server/wm/WindowState.java
index 4d53cea..e6c1e98 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -463,8 +463,8 @@
         mHaveFrame = true;
 
         TaskStack stack = mAppToken != null ? getStack() : null;
-        if (stack != null && stack.hasSibling()) {
-            mContainingFrame.set(getStackBounds(stack));
+        if (stack != null && !stack.isFullscreen()) {
+            getStackBounds(stack, mContainingFrame);
             if (mUnderStatusBar) {
                 mContainingFrame.top = pf.top;
             }
@@ -723,15 +723,16 @@
         return mDisplayContent.getHomeStack();
     }
 
-    Rect getStackBounds() {
-        return getStackBounds(getStack());
+    void getStackBounds(Rect bounds) {
+        getStackBounds(getStack(), bounds);
     }
 
-    private Rect getStackBounds(TaskStack stack) {
+    private void getStackBounds(TaskStack stack, Rect bounds) {
         if (stack != null) {
-            return stack.mStackBox.mBounds;
+            stack.getBounds(bounds);
+            return;
         }
-        return mFrame;
+        bounds.set(mFrame);
     }
 
     public long getInputDispatchingTimeoutNanos() {
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
similarity index 100%
rename from services/java/com/android/server/wm/WindowStateAnimator.java
rename to services/core/java/com/android/server/wm/WindowStateAnimator.java
diff --git a/services/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
similarity index 100%
rename from services/java/com/android/server/wm/WindowToken.java
rename to services/core/java/com/android/server/wm/WindowToken.java
diff --git a/services/core/java/service.mk b/services/core/java/service.mk
new file mode 100644
index 0000000..4cb411b
--- /dev/null
+++ b/services/core/java/service.mk
@@ -0,0 +1,6 @@
+SUB_DIR := core/java
+
+LOCAL_SRC_FILES += \
+      $(call all-java-files-under,$(SUB_DIR)) \
+      $(SUB_DIR)/com/android/server/EventLogTags.logtags \
+      $(SUB_DIR)/com/android/server/am/EventLogTags.logtags
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
new file mode 100644
index 0000000..1a3ce63
--- /dev/null
+++ b/services/core/jni/Android.mk
@@ -0,0 +1,56 @@
+# This file is included by the top level services directory to collect source
+# files
+LOCAL_REL_DIR := core/jni
+
+LOCAL_SRC_FILES += \
+    $(LOCAL_REL_DIR)/com_android_server_AlarmManagerService.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_AssetAtlasService.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_input_InputApplicationHandle.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_input_InputManagerService.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_input_InputWindowHandle.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_lights_LightsService.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_power_PowerManagerService.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_SerialService.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_SystemServer.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_UsbDeviceManager.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_UsbHostManager.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_VibratorService.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_location_GpsLocationProvider.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_location_FlpHardwareProvider.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \
+    $(LOCAL_REL_DIR)/onload.cpp
+
+LOCAL_C_INCLUDES += \
+    $(JNI_H_INCLUDE) \
+    frameworks/base/services \
+    frameworks/base/libs \
+    frameworks/base/core/jni \
+    frameworks/native/services \
+    external/skia/include/core \
+    libcore/include \
+    libcore/include/libsuspend \
+	$(call include-path-for, libhardware)/hardware \
+	$(call include-path-for, libhardware_legacy)/hardware_legacy \
+
+LOCAL_SHARED_LIBRARIES += \
+    libandroid_runtime \
+    libandroidfw \
+    libbinder \
+    libcutils \
+    liblog \
+    libhardware \
+    libhardware_legacy \
+    libnativehelper \
+    libutils \
+    libui \
+    libinput \
+    libinputservice \
+    libsensorservice \
+    libskia \
+    libgui \
+    libusbhost \
+    libsuspend \
+    libEGL \
+    libGLESv2
+
diff --git a/services/jni/com_android_server_AlarmManagerService.cpp b/services/core/jni/com_android_server_AlarmManagerService.cpp
similarity index 100%
rename from services/jni/com_android_server_AlarmManagerService.cpp
rename to services/core/jni/com_android_server_AlarmManagerService.cpp
diff --git a/services/jni/com_android_server_AssetAtlasService.cpp b/services/core/jni/com_android_server_AssetAtlasService.cpp
similarity index 100%
rename from services/jni/com_android_server_AssetAtlasService.cpp
rename to services/core/jni/com_android_server_AssetAtlasService.cpp
diff --git a/services/jni/com_android_server_ConsumerIrService.cpp b/services/core/jni/com_android_server_ConsumerIrService.cpp
similarity index 100%
rename from services/jni/com_android_server_ConsumerIrService.cpp
rename to services/core/jni/com_android_server_ConsumerIrService.cpp
diff --git a/services/jni/com_android_server_SerialService.cpp b/services/core/jni/com_android_server_SerialService.cpp
similarity index 100%
rename from services/jni/com_android_server_SerialService.cpp
rename to services/core/jni/com_android_server_SerialService.cpp
diff --git a/services/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
similarity index 100%
rename from services/jni/com_android_server_SystemServer.cpp
rename to services/core/jni/com_android_server_SystemServer.cpp
diff --git a/services/jni/com_android_server_UsbDeviceManager.cpp b/services/core/jni/com_android_server_UsbDeviceManager.cpp
similarity index 100%
rename from services/jni/com_android_server_UsbDeviceManager.cpp
rename to services/core/jni/com_android_server_UsbDeviceManager.cpp
diff --git a/services/jni/com_android_server_UsbHostManager.cpp b/services/core/jni/com_android_server_UsbHostManager.cpp
similarity index 100%
rename from services/jni/com_android_server_UsbHostManager.cpp
rename to services/core/jni/com_android_server_UsbHostManager.cpp
diff --git a/services/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
similarity index 100%
rename from services/jni/com_android_server_VibratorService.cpp
rename to services/core/jni/com_android_server_VibratorService.cpp
diff --git a/services/jni/com_android_server_connectivity_Vpn.cpp b/services/core/jni/com_android_server_connectivity_Vpn.cpp
similarity index 100%
rename from services/jni/com_android_server_connectivity_Vpn.cpp
rename to services/core/jni/com_android_server_connectivity_Vpn.cpp
diff --git a/services/jni/com_android_server_input_InputApplicationHandle.cpp b/services/core/jni/com_android_server_input_InputApplicationHandle.cpp
similarity index 100%
rename from services/jni/com_android_server_input_InputApplicationHandle.cpp
rename to services/core/jni/com_android_server_input_InputApplicationHandle.cpp
diff --git a/services/jni/com_android_server_input_InputApplicationHandle.h b/services/core/jni/com_android_server_input_InputApplicationHandle.h
similarity index 100%
rename from services/jni/com_android_server_input_InputApplicationHandle.h
rename to services/core/jni/com_android_server_input_InputApplicationHandle.h
diff --git a/services/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
similarity index 100%
rename from services/jni/com_android_server_input_InputManagerService.cpp
rename to services/core/jni/com_android_server_input_InputManagerService.cpp
diff --git a/services/jni/com_android_server_input_InputWindowHandle.cpp b/services/core/jni/com_android_server_input_InputWindowHandle.cpp
similarity index 100%
rename from services/jni/com_android_server_input_InputWindowHandle.cpp
rename to services/core/jni/com_android_server_input_InputWindowHandle.cpp
diff --git a/services/jni/com_android_server_input_InputWindowHandle.h b/services/core/jni/com_android_server_input_InputWindowHandle.h
similarity index 100%
rename from services/jni/com_android_server_input_InputWindowHandle.h
rename to services/core/jni/com_android_server_input_InputWindowHandle.h
diff --git a/services/jni/com_android_server_LightsService.cpp b/services/core/jni/com_android_server_lights_LightsService.cpp
similarity index 97%
rename from services/jni/com_android_server_LightsService.cpp
rename to services/core/jni/com_android_server_lights_LightsService.cpp
index 401e1aa..ea03cfa 100644
--- a/services/jni/com_android_server_LightsService.cpp
+++ b/services/core/jni/com_android_server_lights_LightsService.cpp
@@ -134,7 +134,7 @@
 
 int register_android_server_LightsService(JNIEnv *env)
 {
-    return jniRegisterNativeMethods(env, "com/android/server/LightsService",
+    return jniRegisterNativeMethods(env, "com/android/server/lights/LightsService",
             method_table, NELEM(method_table));
 }
 
diff --git a/services/jni/com_android_server_location_FlpHardwareProvider.cpp b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
similarity index 100%
rename from services/jni/com_android_server_location_FlpHardwareProvider.cpp
rename to services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
diff --git a/services/jni/com_android_server_location_GpsLocationProvider.cpp b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
similarity index 100%
rename from services/jni/com_android_server_location_GpsLocationProvider.cpp
rename to services/core/jni/com_android_server_location_GpsLocationProvider.cpp
diff --git a/services/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
similarity index 100%
rename from services/jni/com_android_server_power_PowerManagerService.cpp
rename to services/core/jni/com_android_server_power_PowerManagerService.cpp
diff --git a/services/jni/com_android_server_power_PowerManagerService.h b/services/core/jni/com_android_server_power_PowerManagerService.h
similarity index 100%
rename from services/jni/com_android_server_power_PowerManagerService.h
rename to services/core/jni/com_android_server_power_PowerManagerService.h
diff --git a/services/jni/onload.cpp b/services/core/jni/onload.cpp
similarity index 100%
rename from services/jni/onload.cpp
rename to services/core/jni/onload.cpp
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
similarity index 89%
rename from services/java/com/android/server/DevicePolicyManagerService.java
rename to services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 2bb99d6..af36246 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.devicepolicy;
 
 import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
 
@@ -117,7 +117,7 @@
  */
 public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
 
-    private static final String TAG = "DevicePolicyManagerService";
+    private static final String LOG_TAG = "DevicePolicyManagerService";
 
     private static final String DEVICE_POLICIES_XML = "device_policies.xml";
 
@@ -186,7 +186,7 @@
                     getSendingUserId());
             if (Intent.ACTION_BOOT_COMPLETED.equals(action)
                     || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
-                if (DBG) Slog.v(TAG, "Sending password expiration notifications for action "
+                if (DBG) Slog.v(LOG_TAG, "Sending password expiration notifications for action "
                         + action + " for user " + userHandle);
                 mHandler.post(new Runnable() {
                     public void run() {
@@ -218,6 +218,28 @@
     };
 
     static class ActiveAdmin {
+        private static final String TAG_DISABLE_KEYGUARD_FEATURES = "disable-keyguard-features";
+        private static final String TAG_DISABLE_CAMERA = "disable-camera";
+        private static final String TAG_ENCRYPTION_REQUESTED = "encryption-requested";
+        private static final String TAG_PASSWORD_EXPIRATION_DATE = "password-expiration-date";
+        private static final String TAG_PASSWORD_EXPIRATION_TIMEOUT = "password-expiration-timeout";
+        private static final String TAG_GLOBAL_PROXY_EXCLUSION_LIST = "global-proxy-exclusion-list";
+        private static final String TAG_GLOBAL_PROXY_SPEC = "global-proxy-spec";
+        private static final String TAG_SPECIFIES_GLOBAL_PROXY = "specifies-global-proxy";
+        private static final String TAG_MAX_FAILED_PASSWORD_WIPE = "max-failed-password-wipe";
+        private static final String TAG_MAX_TIME_TO_UNLOCK = "max-time-to-unlock";
+        private static final String TAG_MIN_PASSWORD_NONLETTER = "min-password-nonletter";
+        private static final String TAG_MIN_PASSWORD_SYMBOLS = "min-password-symbols";
+        private static final String TAG_MIN_PASSWORD_NUMERIC = "min-password-numeric";
+        private static final String TAG_MIN_PASSWORD_LETTERS = "min-password-letters";
+        private static final String TAG_MIN_PASSWORD_LOWERCASE = "min-password-lowercase";
+        private static final String TAG_MIN_PASSWORD_UPPERCASE = "min-password-uppercase";
+        private static final String TAG_PASSWORD_HISTORY_LENGTH = "password-history-length";
+        private static final String TAG_MIN_PASSWORD_LENGTH = "min-password-length";
+        private static final String ATTR_VALUE = "value";
+        private static final String TAG_PASSWORD_QUALITY = "password-quality";
+        private static final String TAG_POLICIES = "policies";
+
         final DeviceAdminInfo info;
 
         int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
@@ -281,103 +303,103 @@
 
         void writeToXml(XmlSerializer out)
                 throws IllegalArgumentException, IllegalStateException, IOException {
-            out.startTag(null, "policies");
+            out.startTag(null, TAG_POLICIES);
             info.writePoliciesToXml(out);
-            out.endTag(null, "policies");
+            out.endTag(null, TAG_POLICIES);
             if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
-                out.startTag(null, "password-quality");
-                out.attribute(null, "value", Integer.toString(passwordQuality));
-                out.endTag(null, "password-quality");
+                out.startTag(null, TAG_PASSWORD_QUALITY);
+                out.attribute(null, ATTR_VALUE, Integer.toString(passwordQuality));
+                out.endTag(null, TAG_PASSWORD_QUALITY);
                 if (minimumPasswordLength != DEF_MINIMUM_PASSWORD_LENGTH) {
-                    out.startTag(null, "min-password-length");
-                    out.attribute(null, "value", Integer.toString(minimumPasswordLength));
-                    out.endTag(null, "min-password-length");
+                    out.startTag(null, TAG_MIN_PASSWORD_LENGTH);
+                    out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordLength));
+                    out.endTag(null, TAG_MIN_PASSWORD_LENGTH);
                 }
                 if(passwordHistoryLength != DEF_PASSWORD_HISTORY_LENGTH) {
-                    out.startTag(null, "password-history-length");
-                    out.attribute(null, "value", Integer.toString(passwordHistoryLength));
-                    out.endTag(null, "password-history-length");
+                    out.startTag(null, TAG_PASSWORD_HISTORY_LENGTH);
+                    out.attribute(null, ATTR_VALUE, Integer.toString(passwordHistoryLength));
+                    out.endTag(null, TAG_PASSWORD_HISTORY_LENGTH);
                 }
                 if (minimumPasswordUpperCase != DEF_MINIMUM_PASSWORD_UPPER_CASE) {
-                    out.startTag(null, "min-password-uppercase");
-                    out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase));
-                    out.endTag(null, "min-password-uppercase");
+                    out.startTag(null, TAG_MIN_PASSWORD_UPPERCASE);
+                    out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordUpperCase));
+                    out.endTag(null, TAG_MIN_PASSWORD_UPPERCASE);
                 }
                 if (minimumPasswordLowerCase != DEF_MINIMUM_PASSWORD_LOWER_CASE) {
-                    out.startTag(null, "min-password-lowercase");
-                    out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase));
-                    out.endTag(null, "min-password-lowercase");
+                    out.startTag(null, TAG_MIN_PASSWORD_LOWERCASE);
+                    out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordLowerCase));
+                    out.endTag(null, TAG_MIN_PASSWORD_LOWERCASE);
                 }
                 if (minimumPasswordLetters != DEF_MINIMUM_PASSWORD_LETTERS) {
-                    out.startTag(null, "min-password-letters");
-                    out.attribute(null, "value", Integer.toString(minimumPasswordLetters));
-                    out.endTag(null, "min-password-letters");
+                    out.startTag(null, TAG_MIN_PASSWORD_LETTERS);
+                    out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordLetters));
+                    out.endTag(null, TAG_MIN_PASSWORD_LETTERS);
                 }
                 if (minimumPasswordNumeric != DEF_MINIMUM_PASSWORD_NUMERIC) {
-                    out.startTag(null, "min-password-numeric");
-                    out.attribute(null, "value", Integer.toString(minimumPasswordNumeric));
-                    out.endTag(null, "min-password-numeric");
+                    out.startTag(null, TAG_MIN_PASSWORD_NUMERIC);
+                    out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordNumeric));
+                    out.endTag(null, TAG_MIN_PASSWORD_NUMERIC);
                 }
                 if (minimumPasswordSymbols != DEF_MINIMUM_PASSWORD_SYMBOLS) {
-                    out.startTag(null, "min-password-symbols");
-                    out.attribute(null, "value", Integer.toString(minimumPasswordSymbols));
-                    out.endTag(null, "min-password-symbols");
+                    out.startTag(null, TAG_MIN_PASSWORD_SYMBOLS);
+                    out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordSymbols));
+                    out.endTag(null, TAG_MIN_PASSWORD_SYMBOLS);
                 }
                 if (minimumPasswordNonLetter > DEF_MINIMUM_PASSWORD_NON_LETTER) {
-                    out.startTag(null, "min-password-nonletter");
-                    out.attribute(null, "value", Integer.toString(minimumPasswordNonLetter));
-                    out.endTag(null, "min-password-nonletter");
+                    out.startTag(null, TAG_MIN_PASSWORD_NONLETTER);
+                    out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordNonLetter));
+                    out.endTag(null, TAG_MIN_PASSWORD_NONLETTER);
                 }
             }
             if (maximumTimeToUnlock != DEF_MAXIMUM_TIME_TO_UNLOCK) {
-                out.startTag(null, "max-time-to-unlock");
-                out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
-                out.endTag(null, "max-time-to-unlock");
+                out.startTag(null, TAG_MAX_TIME_TO_UNLOCK);
+                out.attribute(null, ATTR_VALUE, Long.toString(maximumTimeToUnlock));
+                out.endTag(null, TAG_MAX_TIME_TO_UNLOCK);
             }
             if (maximumFailedPasswordsForWipe != DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) {
-                out.startTag(null, "max-failed-password-wipe");
-                out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
-                out.endTag(null, "max-failed-password-wipe");
+                out.startTag(null, TAG_MAX_FAILED_PASSWORD_WIPE);
+                out.attribute(null, ATTR_VALUE, Integer.toString(maximumFailedPasswordsForWipe));
+                out.endTag(null, TAG_MAX_FAILED_PASSWORD_WIPE);
             }
             if (specifiesGlobalProxy) {
-                out.startTag(null, "specifies-global-proxy");
-                out.attribute(null, "value", Boolean.toString(specifiesGlobalProxy));
-                out.endTag(null, "specifies_global_proxy");
+                out.startTag(null, TAG_SPECIFIES_GLOBAL_PROXY);
+                out.attribute(null, ATTR_VALUE, Boolean.toString(specifiesGlobalProxy));
+                out.endTag(null, TAG_SPECIFIES_GLOBAL_PROXY);
                 if (globalProxySpec != null) {
-                    out.startTag(null, "global-proxy-spec");
-                    out.attribute(null, "value", globalProxySpec);
-                    out.endTag(null, "global-proxy-spec");
+                    out.startTag(null, TAG_GLOBAL_PROXY_SPEC);
+                    out.attribute(null, ATTR_VALUE, globalProxySpec);
+                    out.endTag(null, TAG_GLOBAL_PROXY_SPEC);
                 }
                 if (globalProxyExclusionList != null) {
-                    out.startTag(null, "global-proxy-exclusion-list");
-                    out.attribute(null, "value", globalProxyExclusionList);
-                    out.endTag(null, "global-proxy-exclusion-list");
+                    out.startTag(null, TAG_GLOBAL_PROXY_EXCLUSION_LIST);
+                    out.attribute(null, ATTR_VALUE, globalProxyExclusionList);
+                    out.endTag(null, TAG_GLOBAL_PROXY_EXCLUSION_LIST);
                 }
             }
             if (passwordExpirationTimeout != DEF_PASSWORD_EXPIRATION_TIMEOUT) {
-                out.startTag(null, "password-expiration-timeout");
-                out.attribute(null, "value", Long.toString(passwordExpirationTimeout));
-                out.endTag(null, "password-expiration-timeout");
+                out.startTag(null, TAG_PASSWORD_EXPIRATION_TIMEOUT);
+                out.attribute(null, ATTR_VALUE, Long.toString(passwordExpirationTimeout));
+                out.endTag(null, TAG_PASSWORD_EXPIRATION_TIMEOUT);
             }
             if (passwordExpirationDate != DEF_PASSWORD_EXPIRATION_DATE) {
-                out.startTag(null, "password-expiration-date");
-                out.attribute(null, "value", Long.toString(passwordExpirationDate));
-                out.endTag(null, "password-expiration-date");
+                out.startTag(null, TAG_PASSWORD_EXPIRATION_DATE);
+                out.attribute(null, ATTR_VALUE, Long.toString(passwordExpirationDate));
+                out.endTag(null, TAG_PASSWORD_EXPIRATION_DATE);
             }
             if (encryptionRequested) {
-                out.startTag(null, "encryption-requested");
-                out.attribute(null, "value", Boolean.toString(encryptionRequested));
-                out.endTag(null, "encryption-requested");
+                out.startTag(null, TAG_ENCRYPTION_REQUESTED);
+                out.attribute(null, ATTR_VALUE, Boolean.toString(encryptionRequested));
+                out.endTag(null, TAG_ENCRYPTION_REQUESTED);
             }
             if (disableCamera) {
-                out.startTag(null, "disable-camera");
-                out.attribute(null, "value", Boolean.toString(disableCamera));
-                out.endTag(null, "disable-camera");
+                out.startTag(null, TAG_DISABLE_CAMERA);
+                out.attribute(null, ATTR_VALUE, Boolean.toString(disableCamera));
+                out.endTag(null, TAG_DISABLE_CAMERA);
             }
             if (disabledKeyguardFeatures != DEF_KEYGUARD_FEATURES_DISABLED) {
-                out.startTag(null, "disable-keyguard-features");
-                out.attribute(null, "value", Integer.toString(disabledKeyguardFeatures));
-                out.endTag(null, "disable-keyguard-features");
+                out.startTag(null, TAG_DISABLE_KEYGUARD_FEATURES);
+                out.attribute(null, ATTR_VALUE, Integer.toString(disabledKeyguardFeatures));
+                out.endTag(null, TAG_DISABLE_KEYGUARD_FEATURES);
             }
         }
 
@@ -391,67 +413,67 @@
                     continue;
                 }
                 String tag = parser.getName();
-                if ("policies".equals(tag)) {
+                if (TAG_POLICIES.equals(tag)) {
                     info.readPoliciesFromXml(parser);
-                } else if ("password-quality".equals(tag)) {
+                } else if (TAG_PASSWORD_QUALITY.equals(tag)) {
                     passwordQuality = Integer.parseInt(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("min-password-length".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_MIN_PASSWORD_LENGTH.equals(tag)) {
                     minimumPasswordLength = Integer.parseInt(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("password-history-length".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_PASSWORD_HISTORY_LENGTH.equals(tag)) {
                     passwordHistoryLength = Integer.parseInt(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("min-password-uppercase".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_MIN_PASSWORD_UPPERCASE.equals(tag)) {
                     minimumPasswordUpperCase = Integer.parseInt(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("min-password-lowercase".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_MIN_PASSWORD_LOWERCASE.equals(tag)) {
                     minimumPasswordLowerCase = Integer.parseInt(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("min-password-letters".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_MIN_PASSWORD_LETTERS.equals(tag)) {
                     minimumPasswordLetters = Integer.parseInt(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("min-password-numeric".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_MIN_PASSWORD_NUMERIC.equals(tag)) {
                     minimumPasswordNumeric = Integer.parseInt(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("min-password-symbols".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_MIN_PASSWORD_SYMBOLS.equals(tag)) {
                     minimumPasswordSymbols = Integer.parseInt(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("min-password-nonletter".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_MIN_PASSWORD_NONLETTER.equals(tag)) {
                     minimumPasswordNonLetter = Integer.parseInt(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("max-time-to-unlock".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_MAX_TIME_TO_UNLOCK.equals(tag)) {
                     maximumTimeToUnlock = Long.parseLong(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("max-failed-password-wipe".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_MAX_FAILED_PASSWORD_WIPE.equals(tag)) {
                     maximumFailedPasswordsForWipe = Integer.parseInt(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("specifies-global-proxy".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_SPECIFIES_GLOBAL_PROXY.equals(tag)) {
                     specifiesGlobalProxy = Boolean.parseBoolean(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("global-proxy-spec".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_GLOBAL_PROXY_SPEC.equals(tag)) {
                     globalProxySpec =
-                        parser.getAttributeValue(null, "value");
-                } else if ("global-proxy-exclusion-list".equals(tag)) {
+                        parser.getAttributeValue(null, ATTR_VALUE);
+                } else if (TAG_GLOBAL_PROXY_EXCLUSION_LIST.equals(tag)) {
                     globalProxyExclusionList =
-                        parser.getAttributeValue(null, "value");
-                } else if ("password-expiration-timeout".equals(tag)) {
+                        parser.getAttributeValue(null, ATTR_VALUE);
+                } else if (TAG_PASSWORD_EXPIRATION_TIMEOUT.equals(tag)) {
                     passwordExpirationTimeout = Long.parseLong(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("password-expiration-date".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_PASSWORD_EXPIRATION_DATE.equals(tag)) {
                     passwordExpirationDate = Long.parseLong(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("encryption-requested".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_ENCRYPTION_REQUESTED.equals(tag)) {
                     encryptionRequested = Boolean.parseBoolean(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("disable-camera".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_DISABLE_CAMERA.equals(tag)) {
                     disableCamera = Boolean.parseBoolean(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("disable-keyguard-features".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_DISABLE_KEYGUARD_FEATURES.equals(tag)) {
                     disabledKeyguardFeatures = Integer.parseInt(
-                            parser.getAttributeValue(null, "value"));
+                            parser.getAttributeValue(null, ATTR_VALUE));
                 } else {
-                    Slog.w(TAG, "Unknown admin tag: " + tag);
+                    Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
                 }
                 XmlUtils.skipCurrentTag(parser);
             }
@@ -513,7 +535,7 @@
 
     private void handlePackagesChanged(int userHandle) {
         boolean removed = false;
-        if (DBG) Slog.d(TAG, "Handling package changes for user " + userHandle);
+        if (DBG) Slog.d(LOG_TAG, "Handling package changes for user " + userHandle);
         DevicePolicyData policy = getUserData(userHandle);
         IPackageManager pm = AppGlobals.getPackageManager();
         for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
@@ -585,7 +607,7 @@
     void removeUserData(int userHandle) {
         synchronized (this) {
             if (userHandle == UserHandle.USER_OWNER) {
-                Slog.w(TAG, "Tried to remove device policy file for user 0! Ignoring.");
+                Slog.w(LOG_TAG, "Tried to remove device policy file for user 0! Ignoring.");
                 return;
             }
             DevicePolicyData policy = mUserData.get(userHandle);
@@ -595,7 +617,7 @@
             File policyFile = new File(Environment.getUserSystemDirectory(userHandle),
                     DEVICE_POLICIES_XML);
             policyFile.delete();
-            Slog.i(TAG, "Removed device policy file " + policyFile.getAbsolutePath());
+            Slog.i(LOG_TAG, "Removed device policy file " + policyFile.getAbsolutePath());
         }
     }
 
@@ -792,10 +814,12 @@
         try {
             return new DeviceAdminInfo(mContext, infos.get(0));
         } catch (XmlPullParserException e) {
-            Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e);
+            Slog.w(LOG_TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName,
+                    e);
             return null;
         } catch (IOException e) {
-            Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e);
+            Slog.w(LOG_TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName,
+                    e);
             return null;
         }
     }
@@ -922,7 +946,7 @@
                                 ComponentName.unflattenFromString(name), userHandle);
                         if (DBG && (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid)
                                 != userHandle)) {
-                            Slog.w(TAG, "findAdmin returned an incorrect uid "
+                            Slog.w(LOG_TAG, "findAdmin returned an incorrect uid "
                                     + dai.getActivityInfo().applicationInfo.uid + " for user "
                                     + userHandle);
                         }
@@ -933,7 +957,7 @@
                             policy.mAdminList.add(ap);
                         }
                     } catch (RuntimeException e) {
-                        Slog.w(TAG, "Failed loading admin " + name, e);
+                        Slog.w(LOG_TAG, "Failed loading admin " + name, e);
                     }
                 } else if ("failed-password-attempts".equals(tag)) {
                     policy.mFailedPasswordAttempts = Integer.parseInt(
@@ -962,22 +986,22 @@
                             parser.getAttributeValue(null, "nonletter"));
                     XmlUtils.skipCurrentTag(parser);
                 } else {
-                    Slog.w(TAG, "Unknown tag: " + tag);
+                    Slog.w(LOG_TAG, "Unknown tag: " + tag);
                     XmlUtils.skipCurrentTag(parser);
                 }
             }
         } catch (NullPointerException e) {
-            Slog.w(TAG, "failed parsing " + file + " " + e);
+            Slog.w(LOG_TAG, "failed parsing " + file + " " + e);
         } catch (NumberFormatException e) {
-            Slog.w(TAG, "failed parsing " + file + " " + e);
+            Slog.w(LOG_TAG, "failed parsing " + file + " " + e);
         } catch (XmlPullParserException e) {
-            Slog.w(TAG, "failed parsing " + file + " " + e);
+            Slog.w(LOG_TAG, "failed parsing " + file + " " + e);
         } catch (FileNotFoundException e) {
             // Don't be noisy, this is normal if we haven't defined any policies.
         } catch (IOException e) {
-            Slog.w(TAG, "failed parsing " + file + " " + e);
+            Slog.w(LOG_TAG, "failed parsing " + file + " " + e);
         } catch (IndexOutOfBoundsException e) {
-            Slog.w(TAG, "failed parsing " + file + " " + e);
+            Slog.w(LOG_TAG, "failed parsing " + file + " " + e);
         }
         try {
             if (stream != null) {
@@ -993,7 +1017,7 @@
         // never normally happen.
         LockPatternUtils utils = new LockPatternUtils(mContext);
         if (utils.getActivePasswordQuality() < policy.mActivePasswordQuality) {
-            Slog.w(TAG, "Active password quality 0x"
+            Slog.w(LOG_TAG, "Active password quality 0x"
                     + Integer.toHexString(policy.mActivePasswordQuality)
                     + " does not match actual quality 0x"
                     + Integer.toHexString(utils.getActivePasswordQuality()));
@@ -1037,7 +1061,7 @@
                 }
             }
             if (!haveOwner) {
-                Slog.w(TAG, "Previous password owner " + policy.mPasswordOwner
+                Slog.w(LOG_TAG, "Previous password owner " + policy.mPasswordOwner
                         + " no longer active; disabling");
                 policy.mPasswordOwner = -1;
             }
@@ -1057,7 +1081,7 @@
             long token = Binder.clearCallingIdentity();
             try {
                 String value = cameraDisabled ? "1" : "0";
-                if (DBG) Slog.v(TAG, "Change in camera state ["
+                if (DBG) Slog.v(LOG_TAG, "Change in camera state ["
                         + SYSTEM_PROP_DISABLE_CAMERA + "] = " + value);
                 SystemProperties.set(SYSTEM_PROP_DISABLE_CAMERA, value);
             } finally {
@@ -1173,7 +1197,8 @@
         synchronized (this) {
             long ident = Binder.clearCallingIdentity();
             try {
-                if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) {
+                if (!refreshing
+                        && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) {
                     throw new IllegalArgumentException("Admin is already added");
                 }
                 ActiveAdmin newAdmin = new ActiveAdmin(info);
@@ -1443,7 +1468,7 @@
             ap.passwordExpirationDate = expiration;
             ap.passwordExpirationTimeout = timeout;
             if (timeout > 0L) {
-                Slog.w(TAG, "setPasswordExpiration(): password will expire on "
+                Slog.w(LOG_TAG, "setPasswordExpiration(): password will expire on "
                         + DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)
                         .format(new Date(expiration)));
             }
@@ -1789,11 +1814,11 @@
                 return true;
             }
             return policy.mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null, userHandle)
-                    && policy.mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null, userHandle)
-                    && policy.mActivePasswordLetters >= getPasswordMinimumLetters(null, userHandle)
-                    && policy.mActivePasswordNumeric >= getPasswordMinimumNumeric(null, userHandle)
-                    && policy.mActivePasswordSymbols >= getPasswordMinimumSymbols(null, userHandle)
-                    && policy.mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null, userHandle);
+                && policy.mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null, userHandle)
+                && policy.mActivePasswordLetters >= getPasswordMinimumLetters(null, userHandle)
+                && policy.mActivePasswordNumeric >= getPasswordMinimumNumeric(null, userHandle)
+                && policy.mActivePasswordSymbols >= getPasswordMinimumSymbols(null, userHandle)
+                && policy.mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null, userHandle);
         }
     }
 
@@ -1871,7 +1896,7 @@
                 int realQuality = LockPatternUtils.computePasswordQuality(password);
                 if (realQuality < quality
                         && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
-                    Slog.w(TAG, "resetPassword: password quality 0x"
+                    Slog.w(LOG_TAG, "resetPassword: password quality 0x"
                             + Integer.toHexString(realQuality)
                             + " does not meet required quality 0x"
                             + Integer.toHexString(quality));
@@ -1881,7 +1906,7 @@
             }
             int length = getPasswordMinimumLength(null, userHandle);
             if (password.length() < length) {
-                Slog.w(TAG, "resetPassword: password length " + password.length()
+                Slog.w(LOG_TAG, "resetPassword: password length " + password.length()
                         + " does not meet required length " + length);
                 return false;
             }
@@ -1910,40 +1935,40 @@
                 }
                 int neededLetters = getPasswordMinimumLetters(null, userHandle);
                 if(letters < neededLetters) {
-                    Slog.w(TAG, "resetPassword: number of letters " + letters
+                    Slog.w(LOG_TAG, "resetPassword: number of letters " + letters
                             + " does not meet required number of letters " + neededLetters);
                     return false;
                 }
                 int neededNumbers = getPasswordMinimumNumeric(null, userHandle);
                 if (numbers < neededNumbers) {
-                    Slog.w(TAG, "resetPassword: number of numerical digits " + numbers
+                    Slog.w(LOG_TAG, "resetPassword: number of numerical digits " + numbers
                             + " does not meet required number of numerical digits "
                             + neededNumbers);
                     return false;
                 }
                 int neededLowerCase = getPasswordMinimumLowerCase(null, userHandle);
                 if (lowercase < neededLowerCase) {
-                    Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
+                    Slog.w(LOG_TAG, "resetPassword: number of lowercase letters " + lowercase
                             + " does not meet required number of lowercase letters "
                             + neededLowerCase);
                     return false;
                 }
                 int neededUpperCase = getPasswordMinimumUpperCase(null, userHandle);
                 if (uppercase < neededUpperCase) {
-                    Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
+                    Slog.w(LOG_TAG, "resetPassword: number of uppercase letters " + uppercase
                             + " does not meet required number of uppercase letters "
                             + neededUpperCase);
                     return false;
                 }
                 int neededSymbols = getPasswordMinimumSymbols(null, userHandle);
                 if (symbols < neededSymbols) {
-                    Slog.w(TAG, "resetPassword: number of special symbols " + symbols
+                    Slog.w(LOG_TAG, "resetPassword: number of special symbols " + symbols
                             + " does not meet required number of special symbols " + neededSymbols);
                     return false;
                 }
                 int neededNonLetter = getPasswordMinimumNonLetter(null, userHandle);
                 if (nonletter < neededNonLetter) {
-                    Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
+                    Slog.w(LOG_TAG, "resetPassword: number of non-letter characters " + nonletter
                             + " does not meet required number of non-letter characters "
                             + neededNonLetter);
                     return false;
@@ -1954,7 +1979,7 @@
         int callingUid = Binder.getCallingUid();
         DevicePolicyData policy = getUserData(userHandle);
         if (policy.mPasswordOwner >= 0 && policy.mPasswordOwner != callingUid) {
-            Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
+            Slog.w(LOG_TAG, "resetPassword: already set by another uid and not entered by user");
             return false;
         }
 
@@ -2020,7 +2045,7 @@
             try {
                 getIPowerManager().setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs);
             } catch (RemoteException e) {
-                Slog.w(TAG, "Failure talking with power manager", e);
+                Slog.w(LOG_TAG, "Failure talking with power manager", e);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -2095,10 +2120,10 @@
             X509Certificate cert = parseCert(certBuffer);
             pemCert =  Credentials.convertToPem(cert);
         } catch (CertificateException ce) {
-            Log.e(TAG, "Problem converting cert", ce);
+            Log.e(LOG_TAG, "Problem converting cert", ce);
             return false;
         } catch (IOException ioe) {
-            Log.e(TAG, "Problem reading cert", ioe);
+            Log.e(LOG_TAG, "Problem reading cert", ioe);
             return false;
         }
         try {
@@ -2113,7 +2138,7 @@
                 }
             }
         } catch (InterruptedException e1) {
-            Log.w(TAG, "installCaCertsToKeyChain(): ", e1);
+            Log.w(LOG_TAG, "installCaCertsToKeyChain(): ", e1);
             Thread.currentThread().interrupt();
         }
         return false;
@@ -2134,10 +2159,10 @@
             X509Certificate cert = parseCert(certBuffer);
             alias = certStore.getCertificateAlias(cert);
         } catch (CertificateException ce) {
-            Log.e(TAG, "Problem creating X509Certificate", ce);
+            Log.e(LOG_TAG, "Problem creating X509Certificate", ce);
             return;
         } catch (IOException ioe) {
-            Log.e(TAG, "Problem reading certificate", ioe);
+            Log.e(LOG_TAG, "Problem reading certificate", ioe);
             return;
         }
         try {
@@ -2146,13 +2171,13 @@
             try {
                 service.deleteCaCertificate(alias);
             } catch (RemoteException e) {
-                Log.e(TAG, "from CaCertUninstaller: ", e);
+                Log.e(LOG_TAG, "from CaCertUninstaller: ", e);
             } finally {
                 keyChainConnection.close();
                 keyChainConnection = null;
             }
         } catch (InterruptedException ie) {
-            Log.w(TAG, "CaCertUninstaller: ", ie);
+            Log.w(LOG_TAG, "CaCertUninstaller: ", ie);
             Thread.currentThread().interrupt();
         }
     }
@@ -2173,7 +2198,7 @@
             try {
                 RecoverySystem.rebootWipeUserData(mContext);
             } catch (IOException e) {
-                Slog.w(TAG, "Failed requesting data wipe", e);
+                Slog.w(LOG_TAG, "Failed requesting data wipe", e);
             }
         }
     }
@@ -2264,8 +2289,10 @@
             if (p.mActivePasswordQuality != quality || p.mActivePasswordLength != length
                     || p.mFailedPasswordAttempts != 0 || p.mActivePasswordLetters != letters
                     || p.mActivePasswordUpperCase != uppercase
-                    || p.mActivePasswordLowerCase != lowercase || p.mActivePasswordNumeric != numbers
-                    || p.mActivePasswordSymbols != symbols || p.mActivePasswordNonLetter != nonletter) {
+                    || p.mActivePasswordLowerCase != lowercase
+                    || p.mActivePasswordNumeric != numbers
+                    || p.mActivePasswordSymbols != symbols
+                    || p.mActivePasswordNonLetter != nonletter) {
                 long ident = Binder.clearCallingIdentity();
                 try {
                     p.mActivePasswordQuality = quality;
@@ -2387,7 +2414,7 @@
 
             // If the user is not the owner, don't set the global proxy. Fail silently.
             if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
-                Slog.w(TAG, "Only the owner is allowed to set the global proxy. User "
+                Slog.w(LOG_TAG, "Only the owner is allowed to set the global proxy. User "
                         + userHandle + " is not permitted.");
                 return null;
             }
@@ -2468,7 +2495,7 @@
 
         ProxyProperties proxyProperties = new ProxyProperties(data[0], proxyPort, exclusionList);
         if (!proxyProperties.isValid()) {
-            Slog.e(TAG, "Invalid proxy properties, ignoring: " + proxyProperties.toString());
+            Slog.e(LOG_TAG, "Invalid proxy properties, ignoring: " + proxyProperties.toString());
             return;
         }
         Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, data[0]);
@@ -2494,7 +2521,7 @@
             // Only owner can set storage encryption
             if (userHandle != UserHandle.USER_OWNER
                     || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
-                Slog.w(TAG, "Only owner is allowed to set storage encryption. User "
+                Slog.w(LOG_TAG, "Only owner is allowed to set storage encryption. User "
                         + UserHandle.getCallingUserId() + " is not permitted.");
                 return 0;
             }
@@ -2880,7 +2907,7 @@
                     }
                 }
             } catch (NameNotFoundException nnfe) {
-                Slog.w(TAG, "Device Owner package " + packageName + " not installed.");
+                Slog.w(LOG_TAG, "Device Owner package " + packageName + " not installed.");
             }
             return false;
         }
@@ -2905,9 +2932,9 @@
                 mOwnerName = parser.getAttributeValue(null, ATTR_NAME);
                 input.close();
             } catch (XmlPullParserException xppe) {
-                Slog.e(TAG, "Error parsing device-owner file\n" + xppe);
+                Slog.e(LOG_TAG, "Error parsing device-owner file\n" + xppe);
             } catch (IOException ioe) {
-                Slog.e(TAG, "IO Exception when reading device-owner file\n" + ioe);
+                Slog.e(LOG_TAG, "IO Exception when reading device-owner file\n" + ioe);
             }
         }
 
@@ -2935,7 +2962,7 @@
                 out.flush();
                 file.finishWrite(output);
             } catch (IOException ioe) {
-                Slog.e(TAG, "IO Exception when writing device-owner file\n" + ioe);
+                Slog.e(LOG_TAG, "IO Exception when writing device-owner file\n" + ioe);
             }
         }
     }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerSystemService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerSystemService.java
new file mode 100644
index 0000000..160aa39
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerSystemService.java
@@ -0,0 +1,46 @@
+/*
+ * 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.devicepolicy;
+
+import android.content.Context;
+
+import com.android.server.SystemService;
+
+/**
+ * SystemService wrapper for the DevicePolicyManager implementation. Publishes
+ * Context.DEVICE_POLICY_SERVICE.
+ */
+public final class DevicePolicyManagerSystemService extends SystemService {
+    private DevicePolicyManagerService mDevicePolicyManagerImpl;
+
+    @Override
+    public void onCreate(Context context) {
+        mDevicePolicyManagerImpl = new DevicePolicyManagerService(context);
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService(Context.DEVICE_POLICY_SERVICE, mDevicePolicyManagerImpl);
+    }
+
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == PHASE_LOCK_SETTINGS_READY) {
+            mDevicePolicyManagerImpl.systemReady();
+        }
+    }
+}
\ No newline at end of file
diff --git a/services/devicepolicy/java/service.mk b/services/devicepolicy/java/service.mk
new file mode 100644
index 0000000..e64cc96
--- /dev/null
+++ b/services/devicepolicy/java/service.mk
@@ -0,0 +1,11 @@
+# Include only if the service is required
+ifneq ($(findstring devicepolicy,$(REQUIRED_SERVICES)),)
+
+SUB_DIR := devicepolicy/java
+
+LOCAL_SRC_FILES += \
+      $(call all-java-files-under,$(SUB_DIR))
+
+#DEFINED_SERVICES += com.android.server.devicepolicy.DevicePolicyManagerService
+
+endif
diff --git a/services/java/Android.mk b/services/java/Android.mk
deleted file mode 100644
index 8c3d0f0..0000000
--- a/services/java/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# the library
-# ============================================================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-            $(call all-subdir-java-files) \
-	    com/android/server/EventLogTags.logtags \
-	    com/android/server/am/EventLogTags.logtags
-
-LOCAL_MODULE:= services
-
-LOCAL_JAVA_LIBRARIES := android.policy conscrypt telephony-common
-
-include $(BUILD_JAVA_LIBRARY)
-
-include $(BUILD_DROIDDOC)
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
deleted file mode 100644
index 203cca6..0000000
--- a/services/java/com/android/server/AppWidgetService.java
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * Copyright (C) 2007 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.app.ActivityManager;
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.widget.RemoteViews;
-
-import com.android.internal.appwidget.IAppWidgetHost;
-import com.android.internal.appwidget.IAppWidgetService;
-import com.android.internal.os.BackgroundThread;
-import com.android.internal.util.IndentingPrintWriter;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.List;
-import java.util.Locale;
-
-
-/**
- * Redirects calls to this service to the instance of the service for the appropriate user.
- */
-class AppWidgetService extends IAppWidgetService.Stub
-{
-    private static final String TAG = "AppWidgetService";
-
-    Context mContext;
-    Locale mLocale;
-    PackageManager mPackageManager;
-    boolean mSafeMode;
-    private final Handler mSaveStateHandler;
-
-    private final SparseArray<AppWidgetServiceImpl> mAppWidgetServices;
-
-    AppWidgetService(Context context) {
-        mContext = context;
-
-        mSaveStateHandler = BackgroundThread.getHandler();
-
-        mAppWidgetServices = new SparseArray<AppWidgetServiceImpl>(5);
-        AppWidgetServiceImpl primary = new AppWidgetServiceImpl(context, 0, mSaveStateHandler);
-        mAppWidgetServices.append(0, primary);
-    }
-
-    public void systemRunning(boolean safeMode) {
-        mSafeMode = safeMode;
-
-        mAppWidgetServices.get(0).systemReady(safeMode);
-
-        // Register for the boot completed broadcast, so we can send the
-        // ENABLE broacasts. If we try to send them now, they time out,
-        // because the system isn't ready to handle them yet.
-        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
-                new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
-
-        // Register for configuration changes so we can update the names
-        // of the widgets when the locale changes.
-        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
-                new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED), null, null);
-
-        // Register for broadcasts about package install, etc., so we can
-        // update the provider list.
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_PACKAGE_ADDED);
-        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
-        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
-        filter.addDataScheme("package");
-        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
-                filter, null, null);
-        // Register for events related to sdcard installation.
-        IntentFilter sdFilter = new IntentFilter();
-        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
-        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
-        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
-                sdFilter, null, null);
-
-        IntentFilter userFilter = new IntentFilter();
-        userFilter.addAction(Intent.ACTION_USER_REMOVED);
-        userFilter.addAction(Intent.ACTION_USER_STOPPING);
-        mContext.registerReceiver(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
-                    onUserRemoved(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
-                            UserHandle.USER_NULL));
-                } else if (Intent.ACTION_USER_STOPPING.equals(intent.getAction())) {
-                    onUserStopping(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
-                            UserHandle.USER_NULL));
-                }
-            }
-        }, userFilter);
-    }
-
-    @Override
-    public int allocateAppWidgetId(String packageName, int hostId, int userId)
-            throws RemoteException {
-        return getImplForUser(userId).allocateAppWidgetId(packageName, hostId);
-    }
-
-    @Override
-    public int[] getAppWidgetIdsForHost(int hostId, int userId) throws RemoteException {
-        return getImplForUser(userId).getAppWidgetIdsForHost(hostId);
-    }
-
-    @Override
-    public void deleteAppWidgetId(int appWidgetId, int userId) throws RemoteException {
-        getImplForUser(userId).deleteAppWidgetId(appWidgetId);
-    }
-
-    @Override
-    public void deleteHost(int hostId, int userId) throws RemoteException {
-        getImplForUser(userId).deleteHost(hostId);
-    }
-
-    @Override
-    public void deleteAllHosts(int userId) throws RemoteException {
-        getImplForUser(userId).deleteAllHosts();
-    }
-
-    @Override
-    public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options, int userId)
-            throws RemoteException {
-        getImplForUser(userId).bindAppWidgetId(appWidgetId, provider, options);
-    }
-
-    @Override
-    public boolean bindAppWidgetIdIfAllowed(
-            String packageName, int appWidgetId, ComponentName provider, Bundle options, int userId)
-                    throws RemoteException {
-        return getImplForUser(userId).bindAppWidgetIdIfAllowed(
-                packageName, appWidgetId, provider, options);
-    }
-
-    @Override
-    public boolean hasBindAppWidgetPermission(String packageName, int userId)
-            throws RemoteException {
-        return getImplForUser(userId).hasBindAppWidgetPermission(packageName);
-    }
-
-    @Override
-    public void setBindAppWidgetPermission(String packageName, boolean permission, int userId)
-            throws RemoteException {
-        getImplForUser(userId).setBindAppWidgetPermission(packageName, permission);
-    }
-
-    @Override
-    public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection,
-            int userId) throws RemoteException {
-        getImplForUser(userId).bindRemoteViewsService(appWidgetId, intent, connection);
-    }
-
-    @Override
-    public int[] startListening(IAppWidgetHost host, String packageName, int hostId,
-            List<RemoteViews> updatedViews, int userId) throws RemoteException {
-        return getImplForUser(userId).startListening(host, packageName, hostId, updatedViews);
-    }
-
-    public void onUserRemoved(int userId) {
-        if (userId < 1) return;
-        synchronized (mAppWidgetServices) {
-            AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
-            mAppWidgetServices.remove(userId);
-
-            if (impl == null) {
-                AppWidgetServiceImpl.getSettingsFile(userId).delete();
-            } else {
-                impl.onUserRemoved();
-            }
-        }
-    }
-
-    public void onUserStopping(int userId) {
-        if (userId < 1) return;
-        synchronized (mAppWidgetServices) {
-            AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
-            if (impl != null) {
-                mAppWidgetServices.remove(userId);
-                impl.onUserStopping();
-            }
-        }
-    }
-
-    private void checkPermission(int userId) {
-        int realUserId = ActivityManager.handleIncomingUser(
-                Binder.getCallingPid(),
-                Binder.getCallingUid(),
-                userId,
-                false, /* allowAll */
-                true, /* requireFull */
-                this.getClass().getSimpleName(),
-                this.getClass().getPackage().getName());
-    }
-
-    private AppWidgetServiceImpl getImplForUser(int userId) {
-        checkPermission(userId);
-        boolean sendInitial = false;
-        AppWidgetServiceImpl service;
-        synchronized (mAppWidgetServices) {
-            service = mAppWidgetServices.get(userId);
-            if (service == null) {
-                Slog.i(TAG, "Unable to find AppWidgetServiceImpl for user " + userId + ", adding");
-                // TODO: Verify that it's a valid user
-                service = new AppWidgetServiceImpl(mContext, userId, mSaveStateHandler);
-                service.systemReady(mSafeMode);
-                // Assume that BOOT_COMPLETED was received, as this is a non-primary user.
-                mAppWidgetServices.append(userId, service);
-                sendInitial = true;
-            }
-        }
-        if (sendInitial) {
-            service.sendInitialBroadcasts();
-        }
-        return service;
-    }
-
-    @Override
-    public int[] getAppWidgetIds(ComponentName provider, int userId) throws RemoteException {
-        return getImplForUser(userId).getAppWidgetIds(provider);
-    }
-
-    @Override
-    public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId, int userId)
-            throws RemoteException {
-        return getImplForUser(userId).getAppWidgetInfo(appWidgetId);
-    }
-
-    @Override
-    public RemoteViews getAppWidgetViews(int appWidgetId, int userId) throws RemoteException {
-        return getImplForUser(userId).getAppWidgetViews(appWidgetId);
-    }
-
-    @Override
-    public void updateAppWidgetOptions(int appWidgetId, Bundle options, int userId) {
-        getImplForUser(userId).updateAppWidgetOptions(appWidgetId, options);
-    }
-
-    @Override
-    public Bundle getAppWidgetOptions(int appWidgetId, int userId) {
-        return getImplForUser(userId).getAppWidgetOptions(appWidgetId);
-    }
-
-    @Override
-    public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter, int userId)
-            throws RemoteException {
-        return getImplForUser(userId).getInstalledProviders(categoryFilter);
-    }
-
-    @Override
-    public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId, int userId)
-            throws RemoteException {
-        getImplForUser(userId).notifyAppWidgetViewDataChanged(
-                appWidgetIds, viewId);
-    }
-
-    @Override
-    public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views, int userId)
-            throws RemoteException {
-        getImplForUser(userId).partiallyUpdateAppWidgetIds(
-                appWidgetIds, views);
-    }
-
-    @Override
-    public void stopListening(int hostId, int userId) throws RemoteException {
-        getImplForUser(userId).stopListening(hostId);
-    }
-
-    @Override
-    public void unbindRemoteViewsService(int appWidgetId, Intent intent, int userId)
-            throws RemoteException {
-        getImplForUser(userId).unbindRemoteViewsService(
-                appWidgetId, intent);
-    }
-
-    @Override
-    public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views, int userId)
-            throws RemoteException {
-        getImplForUser(userId).updateAppWidgetIds(appWidgetIds, views);
-    }
-
-    @Override
-    public void updateAppWidgetProvider(ComponentName provider, RemoteViews views, int userId)
-            throws RemoteException {
-        getImplForUser(userId).updateAppWidgetProvider(provider, views);
-    }
-
-    @Override
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
-
-        // Dump the state of all the app widget providers
-        synchronized (mAppWidgetServices) {
-            IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
-            for (int i = 0; i < mAppWidgetServices.size(); i++) {
-                pw.println("User: " + mAppWidgetServices.keyAt(i));
-                ipw.increaseIndent();
-                AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
-                service.dump(fd, ipw, args);
-                ipw.decreaseIndent();
-            }
-        }
-    }
-
-    BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            // Slog.d(TAG, "received " + action);
-            if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
-                int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
-                if (userId >= 0) {
-                    getImplForUser(userId).sendInitialBroadcasts();
-                } else {
-                    Slog.w(TAG, "Incorrect user handle supplied in " + intent);
-                }
-            } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
-                for (int i = 0; i < mAppWidgetServices.size(); i++) {
-                    AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
-                    service.onConfigurationChanged();
-                }
-            } else {
-                int sendingUser = getSendingUserId();
-                if (sendingUser == UserHandle.USER_ALL) {
-                    for (int i = 0; i < mAppWidgetServices.size(); i++) {
-                        AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
-                        service.onBroadcastReceived(intent);
-                    }
-                } else {
-                    AppWidgetServiceImpl service = mAppWidgetServices.get(sendingUser);
-                    if (service != null) {
-                        service.onBroadcastReceived(intent);
-                    }
-                }
-            }
-        }
-    };
-}
diff --git a/services/java/com/android/server/display/HeadlessDisplayAdapter.java b/services/java/com/android/server/display/HeadlessDisplayAdapter.java
deleted file mode 100644
index 7a104d7..0000000
--- a/services/java/com/android/server/display/HeadlessDisplayAdapter.java
+++ /dev/null
@@ -1,73 +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;
-
-import android.content.Context;
-import android.os.Handler;
-import android.util.DisplayMetrics;
-import android.view.Display;
-
-/**
- * Provides a fake default display for headless systems.
- * <p>
- * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock.
- * </p>
- */
-final class HeadlessDisplayAdapter extends DisplayAdapter {
-    private static final String TAG = "HeadlessDisplayAdapter";
-
-    // Called with SyncRoot lock held.
-    public HeadlessDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
-            Context context, Handler handler, Listener listener) {
-        super(syncRoot, context, handler, listener, TAG);
-    }
-
-    @Override
-    public void registerLocked() {
-        super.registerLocked();
-        sendDisplayDeviceEventLocked(new HeadlessDisplayDevice(), DISPLAY_DEVICE_EVENT_ADDED);
-    }
-
-    private final class HeadlessDisplayDevice extends DisplayDevice {
-        private DisplayDeviceInfo mInfo;
-
-        public HeadlessDisplayDevice() {
-            super(HeadlessDisplayAdapter.this, null);
-        }
-
-        @Override
-        public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
-            if (mInfo == null) {
-                mInfo = new DisplayDeviceInfo();
-                mInfo.name = getContext().getResources().getString(
-                        com.android.internal.R.string.display_manager_built_in_display_name);
-                mInfo.width = 640;
-                mInfo.height = 480;
-                mInfo.refreshRate = 60;
-                mInfo.densityDpi = DisplayMetrics.DENSITY_DEFAULT;
-                mInfo.xDpi = 160;
-                mInfo.yDpi = 160;
-                mInfo.flags = DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY
-                        | DisplayDeviceInfo.FLAG_SECURE
-                        | DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS;
-                mInfo.type = Display.TYPE_BUILT_IN;
-                mInfo.touch = DisplayDeviceInfo.TOUCH_NONE;
-            }
-            return mInfo;
-        }
-    }
-}
diff --git a/services/java/com/android/server/print/PrintManagerService.java b/services/java/com/android/server/print/PrintManagerService.java
deleted file mode 100644
index 98acc27..0000000
--- a/services/java/com/android/server/print/PrintManagerService.java
+++ /dev/null
@@ -1,656 +0,0 @@
-/*
- * 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.print;
-
-import android.Manifest;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.print.IPrintDocumentAdapter;
-import android.print.IPrintJobStateChangeListener;
-import android.print.IPrintManager;
-import android.print.IPrinterDiscoveryObserver;
-import android.print.PrintAttributes;
-import android.print.PrintJobId;
-import android.print.PrintJobInfo;
-import android.print.PrinterId;
-import android.printservice.PrintServiceInfo;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.SparseArray;
-
-import com.android.internal.R;
-import com.android.internal.content.PackageMonitor;
-import com.android.internal.os.BackgroundThread;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-
-public final class PrintManagerService extends IPrintManager.Stub {
-
-    private static final char COMPONENT_NAME_SEPARATOR = ':';
-
-    private static final String EXTRA_PRINT_SERVICE_COMPONENT_NAME =
-            "EXTRA_PRINT_SERVICE_COMPONENT_NAME";
-
-    private final Object mLock = new Object();
-
-    private final Context mContext;
-
-    private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
-
-    private int mCurrentUserId = UserHandle.USER_OWNER;
-
-    public PrintManagerService(Context context) {
-        mContext = context;
-        registerContentObservers();
-        registerBoradcastReceivers();
-    }
-
-    public void systemRuning() {
-        BackgroundThread.getHandler().post(new Runnable() {
-            @Override
-            public void run() {
-                final UserState userState;
-                synchronized (mLock) {
-                    userState = getCurrentUserStateLocked();
-                    userState.updateIfNeededLocked();
-                }
-                // This is the first time we switch to this user after boot, so
-                // now is the time to remove obsolete print jobs since they
-                // are from the last boot and no application would query them.
-                userState.removeObsoletePrintJobs();
-            }
-        });
-    }
-
-    @Override
-    public Bundle print(String printJobName, IPrintDocumentAdapter adapter,
-            PrintAttributes attributes, String packageName, int appId, int userId) {
-        final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        String resolvedPackageName = resolveCallingPackageNameEnforcingSecurity(packageName);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            return userState.print(printJobName, adapter, attributes,
-                    resolvedPackageName, resolvedAppId);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public List<PrintJobInfo> getPrintJobInfos(int appId, int userId) {
-        final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            return userState.getPrintJobInfos(resolvedAppId);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId, int userId) {
-        final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            return userState.getPrintJobInfo(printJobId, resolvedAppId);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public void cancelPrintJob(PrintJobId printJobId, int appId, int userId) {
-        final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            userState.cancelPrintJob(printJobId, resolvedAppId);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public void restartPrintJob(PrintJobId printJobId, int appId, int userId) {
-        final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            userState.restartPrintJob(printJobId, resolvedAppId);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public List<PrintServiceInfo> getEnabledPrintServices(int userId) {
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            return userState.getEnabledPrintServices();
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public List<PrintServiceInfo> getInstalledPrintServices(int userId) {
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            return userState.getInstalledPrintServices();
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
-            int userId) {
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            userState.createPrinterDiscoverySession(observer);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public void destroyPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
-            int userId) {
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            userState.destroyPrinterDiscoverySession(observer);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public void startPrinterDiscovery(IPrinterDiscoveryObserver observer,
-            List<PrinterId> priorityList, int userId) {
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            userState.startPrinterDiscovery(observer, priorityList);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public void stopPrinterDiscovery(IPrinterDiscoveryObserver observer, int userId) {
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            userState.stopPrinterDiscovery(observer);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public void validatePrinters(List<PrinterId> printerIds, int userId) {
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            userState.validatePrinters(printerIds);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public void startPrinterStateTracking(PrinterId printerId, int userId) {
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            userState.startPrinterStateTracking(printerId);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public void stopPrinterStateTracking(PrinterId printerId, int userId) {
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            userState.stopPrinterStateTracking(printerId);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public void addPrintJobStateChangeListener(IPrintJobStateChangeListener listener,
-            int appId, int userId) throws RemoteException {
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            userState.addPrintJobStateChangeListener(listener, resolvedAppId);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public void removePrintJobStateChangeListener(IPrintJobStateChangeListener listener,
-            int userId) {
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            userState.removePrintJobStateChangeListener(listener);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
-                != PackageManager.PERMISSION_GRANTED) {
-            pw.println("Permission Denial: can't dump PrintManager from from pid="
-                    + Binder.getCallingPid()
-                    + ", uid=" + Binder.getCallingUid());
-            return;
-        }
-
-        synchronized (mLock) {
-            final long identity = Binder.clearCallingIdentity();
-            try {
-                pw.println("PRINT MANAGER STATE (dumpsys print)");
-                final int userStateCount = mUserStates.size();
-                for (int i = 0; i < userStateCount; i++) {
-                    UserState userState = mUserStates.valueAt(i);
-                    userState.dump(fd, pw, "");
-                    pw.println();
-                }
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
-    }
-
-    private void registerContentObservers() {
-        final Uri enabledPrintServicesUri = Settings.Secure.getUriFor(
-                Settings.Secure.ENABLED_PRINT_SERVICES);
-
-        ContentObserver observer = new ContentObserver(BackgroundThread.getHandler()) {
-            @Override
-            public void onChange(boolean selfChange, Uri uri) {
-                if (enabledPrintServicesUri.equals(uri)) {
-                    synchronized (mLock) {
-                        UserState userState = getCurrentUserStateLocked();
-                        userState.updateIfNeededLocked();
-                    }
-                }
-            }
-        };
-
-        mContext.getContentResolver().registerContentObserver(enabledPrintServicesUri,
-                false, observer, UserHandle.USER_ALL);
-    }
-
-    private void registerBoradcastReceivers() {
-        PackageMonitor monitor = new PackageMonitor() {
-            @Override
-            public boolean onPackageChanged(String packageName, int uid, String[] components) {
-                synchronized (mLock) {
-                    UserState userState = getOrCreateUserStateLocked(getChangingUserId());
-                    Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
-                    while (iterator.hasNext()) {
-                        ComponentName componentName = iterator.next();
-                        if (packageName.equals(componentName.getPackageName())) {
-                            userState.updateIfNeededLocked();
-                            return true;
-                        }
-                    }
-                }
-                return false;
-            }
-
-            @Override
-            public void onPackageRemoved(String packageName, int uid) {
-                synchronized (mLock) {
-                    UserState userState = getOrCreateUserStateLocked(getChangingUserId());
-                    Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
-                    while (iterator.hasNext()) {
-                        ComponentName componentName = iterator.next();
-                        if (packageName.equals(componentName.getPackageName())) {
-                            iterator.remove();
-                            persistComponentNamesToSettingLocked(
-                                    Settings.Secure.ENABLED_PRINT_SERVICES,
-                                    userState.getEnabledServices(), getChangingUserId());
-                            userState.updateIfNeededLocked();
-                            return;
-                        }
-                    }
-                }
-            }
-
-            @Override
-            public boolean onHandleForceStop(Intent intent, String[] stoppedPackages,
-                    int uid, boolean doit) {
-                synchronized (mLock) {
-                    UserState userState = getOrCreateUserStateLocked(getChangingUserId());
-                    boolean stoppedSomePackages = false;
-                    Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
-                    while (iterator.hasNext()) {
-                        ComponentName componentName = iterator.next();
-                        String componentPackage = componentName.getPackageName();
-                        for (String stoppedPackage : stoppedPackages) {
-                            if (componentPackage.equals(stoppedPackage)) {
-                                if (!doit) {
-                                    return true;
-                                }
-                                stoppedSomePackages = true;
-                                break;
-                            }
-                        }
-                    }
-                    if (stoppedSomePackages) {
-                        userState.updateIfNeededLocked();
-                    }
-                    return false;
-                }
-            }
-
-            @Override
-            public void onPackageAdded(String packageName, int uid) {
-                Intent intent = new Intent(android.printservice.PrintService.SERVICE_INTERFACE);
-                intent.setPackage(packageName);
-
-                List<ResolveInfo> installedServices = mContext.getPackageManager()
-                        .queryIntentServicesAsUser(intent, PackageManager.GET_SERVICES,
-                                getChangingUserId());
-
-                if (installedServices == null) {
-                    return;
-                }
-
-                final int installedServiceCount = installedServices.size();
-                for (int i = 0; i < installedServiceCount; i++) {
-                    ServiceInfo serviceInfo = installedServices.get(i).serviceInfo;
-                    ComponentName component = new ComponentName(serviceInfo.packageName,
-                            serviceInfo.name);
-                    String label = serviceInfo.loadLabel(mContext.getPackageManager()).toString();
-                    showEnableInstalledPrintServiceNotification(component, label,
-                            getChangingUserId());
-                }
-            }
-
-            private void persistComponentNamesToSettingLocked(String settingName,
-                    Set<ComponentName> componentNames, int userId) {
-                StringBuilder builder = new StringBuilder();
-                for (ComponentName componentName : componentNames) {
-                    if (builder.length() > 0) {
-                        builder.append(COMPONENT_NAME_SEPARATOR);
-                    }
-                    builder.append(componentName.flattenToShortString());
-                }
-                Settings.Secure.putStringForUser(mContext.getContentResolver(),
-                        settingName, builder.toString(), userId);
-            }
-        };
-
-        // package changes
-        monitor.register(mContext, BackgroundThread.getHandler().getLooper(),
-                UserHandle.ALL, true);
-
-        // user changes
-        IntentFilter intentFilter = new IntentFilter();
-        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
-        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
-
-        mContext.registerReceiverAsUser(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                String action = intent.getAction();
-                if (Intent.ACTION_USER_SWITCHED.equals(action)) {
-                    switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
-                } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
-                    removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
-                }
-            }
-        }, UserHandle.ALL, intentFilter, null, BackgroundThread.getHandler());
-    }
-
-    private UserState getCurrentUserStateLocked() {
-        return getOrCreateUserStateLocked(mCurrentUserId);
-    }
-
-    private UserState getOrCreateUserStateLocked(int userId) {
-        UserState userState = mUserStates.get(userId);
-        if (userState == null) {
-            userState = new UserState(mContext, userId, mLock);
-            mUserStates.put(userId, userState);
-        }
-        return userState;
-    }
-
-    private void switchUser(int newUserId) {
-        UserState userState;
-        synchronized (mLock) {
-            if (newUserId == mCurrentUserId) {
-                return;
-            }
-            mCurrentUserId = newUserId;
-            userState = mUserStates.get(mCurrentUserId);
-            if (userState == null) {
-                userState = getCurrentUserStateLocked();
-                userState.updateIfNeededLocked();
-            } else {
-                userState.updateIfNeededLocked();
-            }
-        }
-        // This is the first time we switch to this user after boot, so
-        // now is the time to remove obsolete print jobs since they
-        // are from the last boot and no application would query them.
-        userState.removeObsoletePrintJobs();
-    }
-
-    private void removeUser(int removedUserId) {
-        synchronized (mLock) {
-            UserState userState = mUserStates.get(removedUserId);
-            if (userState != null) {
-                userState.destroyLocked();
-                mUserStates.remove(removedUserId);
-            }
-        }
-    }
-
-    private int resolveCallingAppEnforcingPermissions(int appId) {
-        final int callingUid = Binder.getCallingUid();
-        if (callingUid == 0 || callingUid == Process.SYSTEM_UID
-                || callingUid == Process.SHELL_UID) {
-            return appId;
-        }
-        final int callingAppId = UserHandle.getAppId(callingUid);
-        if (appId == callingAppId) {
-            return appId;
-        }
-        if (mContext.checkCallingPermission(
-                "com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS")
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Call from app " + callingAppId + " as app "
-                    + appId + " without com.android.printspooler.permission"
-                    + ".ACCESS_ALL_PRINT_JOBS");
-        }
-        return appId;
-    }
-
-    private int resolveCallingUserEnforcingPermissions(int userId) {
-        final int callingUid = Binder.getCallingUid();
-        if (callingUid == 0 || callingUid == Process.SYSTEM_UID
-                || callingUid == Process.SHELL_UID) {
-            return userId;
-        }
-        final int callingUserId = UserHandle.getUserId(callingUid);
-        if (callingUserId == userId) {
-            return userId;
-        }
-        if (mContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)
-                != PackageManager.PERMISSION_GRANTED
-            ||  mContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS)
-                != PackageManager.PERMISSION_GRANTED) {
-            if (userId == UserHandle.USER_CURRENT_OR_SELF) {
-                return callingUserId;
-            }
-            throw new SecurityException("Call from user " + callingUserId + " as user "
-                + userId + " without permission INTERACT_ACROSS_USERS or "
-                + "INTERACT_ACROSS_USERS_FULL not allowed.");
-        }
-        if (userId == UserHandle.USER_CURRENT || userId == UserHandle.USER_CURRENT_OR_SELF) {
-            return mCurrentUserId;
-        }
-        throw new IllegalArgumentException("Calling user can be changed to only "
-                + "UserHandle.USER_CURRENT or UserHandle.USER_CURRENT_OR_SELF.");
-    }
-
-    private String resolveCallingPackageNameEnforcingSecurity(String packageName) {
-        if (TextUtils.isEmpty(packageName)) {
-            return null;
-        }
-        String[] packages = mContext.getPackageManager().getPackagesForUid(
-                Binder.getCallingUid());
-        final int packageCount = packages.length;
-        for (int i = 0; i < packageCount; i++) {
-            if (packageName.equals(packages[i])) {
-                return packageName;
-            }
-        }
-        return null;
-    }
-
-    private void showEnableInstalledPrintServiceNotification(ComponentName component,
-            String label, int userId) {
-        UserHandle userHandle = new UserHandle(userId);
-
-        Intent intent = new Intent(Settings.ACTION_PRINT_SETTINGS);
-        intent.putExtra(EXTRA_PRINT_SERVICE_COMPONENT_NAME, component.flattenToString());
-
-        PendingIntent pendingIntent = PendingIntent.getActivityAsUser(mContext, 0, intent,
-                PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT, null, userHandle);
-
-        Notification.Builder builder = new Notification.Builder(mContext)
-                .setSmallIcon(R.drawable.ic_print)
-                .setContentTitle(mContext.getString(R.string.print_service_installed_title, label))
-                .setContentText(mContext.getString(R.string.print_service_installed_message))
-                .setContentIntent(pendingIntent)
-                .setWhen(System.currentTimeMillis())
-                .setAutoCancel(true)
-                .setShowWhen(true);
-
-        NotificationManager notificationManager = (NotificationManager) mContext
-                .getSystemService(Context.NOTIFICATION_SERVICE);
-
-        String notificationTag = getClass().getName() + ":" + component.flattenToString();
-        notificationManager.notifyAsUser(notificationTag, 0, builder.build(),
-                userHandle);
-    }
-}
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
deleted file mode 100644
index d358b4c..0000000
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ /dev/null
@@ -1,523 +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.wm;
-
-import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
-import static com.android.server.wm.WindowManagerService.DEBUG_STACK;
-import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
-import static com.android.server.wm.WindowManagerService.TAG;
-
-import android.app.ActivityManager.StackBoxInfo;
-import android.graphics.Rect;
-import android.graphics.Region;
-import android.os.Debug;
-import android.util.EventLog;
-import android.util.Slog;
-import android.view.Display;
-import android.view.DisplayInfo;
-import com.android.server.EventLogTags;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-
-class DisplayContentList extends ArrayList<DisplayContent> {
-}
-
-/**
- * Utility class for keeping track of the WindowStates and other pertinent contents of a
- * particular Display.
- *
- * IMPORTANT: No method from this class should ever be used without holding
- * WindowManagerService.mWindowMap.
- */
-class DisplayContent {
-
-    /** Unique identifier of this stack. */
-    private final int mDisplayId;
-
-    /** Z-ordered (bottom-most first) list of all Window objects. Assigned to an element
-     * from mDisplayWindows; */
-    private WindowList mWindows = new WindowList();
-
-    // This protects the following display size properties, so that
-    // getDisplaySize() doesn't need to acquire the global lock.  This is
-    // needed because the window manager sometimes needs to use ActivityThread
-    // while it has its global state locked (for example to load animation
-    // resources), but the ActivityThread also needs get the current display
-    // size sometimes when it has its package lock held.
-    //
-    // These will only be modified with both mWindowMap and mDisplaySizeLock
-    // held (in that order) so the window manager doesn't need to acquire this
-    // lock when needing these values in its normal operation.
-    final Object mDisplaySizeLock = new Object();
-    int mInitialDisplayWidth = 0;
-    int mInitialDisplayHeight = 0;
-    int mInitialDisplayDensity = 0;
-    int mBaseDisplayWidth = 0;
-    int mBaseDisplayHeight = 0;
-    int mBaseDisplayDensity = 0;
-    private final DisplayInfo mDisplayInfo = new DisplayInfo();
-    private final Display mDisplay;
-
-    Rect mBaseDisplayRect = new Rect();
-
-    // Accessed directly by all users.
-    boolean layoutNeeded;
-    int pendingLayoutChanges;
-    final boolean isDefaultDisplay;
-
-    /**
-     * Window tokens that are in the process of exiting, but still
-     * on screen for animations.
-     */
-    final ArrayList<WindowToken> mExitingTokens = new ArrayList<WindowToken>();
-
-    /**
-     * Application tokens that are in the process of exiting, but still
-     * on screen for animations.
-     */
-    final AppTokenList mExitingAppTokens = new AppTokenList();
-
-    /** Array containing the home StackBox and possibly one more which would contain apps. Array
-     * is stored in display order with the current bottom stack at 0. */
-    private ArrayList<StackBox> mStackBoxes = new ArrayList<StackBox>();
-
-    /** True when the home StackBox is at the top of mStackBoxes, false otherwise. */
-    private TaskStack mHomeStack = null;
-
-    /** Detect user tapping outside of current focused stack bounds .*/
-    StackTapPointerEventListener mTapDetector;
-
-    /** Detect user tapping outside of current focused stack bounds .*/
-    Region mTouchExcludeRegion = new Region();
-
-    /** Save allocating when retrieving tasks */
-    private ArrayList<Task> mTaskHistory = new ArrayList<Task>();
-
-    /** Save allocating when calculating rects */
-    Rect mTmpRect = new Rect();
-
-    final WindowManagerService mService;
-
-    /**
-     * @param display May not be null.
-     * @param service TODO(cmautner):
-     */
-    DisplayContent(Display display, WindowManagerService service) {
-        mDisplay = display;
-        mDisplayId = display.getDisplayId();
-        display.getDisplayInfo(mDisplayInfo);
-        isDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;
-        mService = service;
-
-        StackBox newBox = new StackBox(service, this, null);
-        mStackBoxes.add(newBox);
-        TaskStack newStack = new TaskStack(service, HOME_STACK_ID, this);
-        newStack.mStackBox = newBox;
-        newBox.mStack = newStack;
-        mHomeStack = newStack;
-    }
-
-    int getDisplayId() {
-        return mDisplayId;
-    }
-
-    WindowList getWindowList() {
-        return mWindows;
-    }
-
-    Display getDisplay() {
-        return mDisplay;
-    }
-
-    DisplayInfo getDisplayInfo() {
-        return mDisplayInfo;
-    }
-
-    /**
-     * Returns true if the specified UID has access to this display.
-     */
-    public boolean hasAccess(int uid) {
-        return mDisplay.hasAccess(uid);
-    }
-
-    boolean homeOnTop() {
-        return mStackBoxes.get(0).mStack != mHomeStack;
-    }
-
-    public boolean isPrivate() {
-        return (mDisplay.getFlags() & Display.FLAG_PRIVATE) != 0;
-    }
-
-    /**
-     * Retrieve the tasks on this display in stack order from the bottommost TaskStack up.
-     * @return All the Tasks, in order, on this display.
-     */
-    ArrayList<Task> getTasks() {
-        return mTaskHistory;
-    }
-
-    void addTask(Task task, boolean toTop) {
-        mTaskHistory.remove(task);
-
-        final int userId = task.mUserId;
-        int taskNdx;
-        final int numTasks = mTaskHistory.size();
-        if (toTop) {
-            for (taskNdx = numTasks - 1; taskNdx >= 0; --taskNdx) {
-                if (mTaskHistory.get(taskNdx).mUserId == userId) {
-                    break;
-                }
-            }
-            ++taskNdx;
-        } else {
-            for (taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
-                if (mTaskHistory.get(taskNdx).mUserId == userId) {
-                    break;
-                }
-            }
-        }
-
-        mTaskHistory.add(taskNdx, task);
-        EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.taskId, toTop ? 1 : 0, taskNdx);
-    }
-
-    void removeTask(Task task) {
-        mTaskHistory.remove(task);
-    }
-
-    TaskStack getHomeStack() {
-        return mHomeStack;
-    }
-
-    void updateDisplayInfo() {
-        mDisplay.getDisplayInfo(mDisplayInfo);
-    }
-
-    void getLogicalDisplayRect(Rect out) {
-        updateDisplayInfo();
-        // Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked.
-        int width = mDisplayInfo.logicalWidth;
-        int left = (mBaseDisplayWidth - width) / 2;
-        int height = mDisplayInfo.logicalHeight;
-        int top = (mBaseDisplayHeight - height) / 2;
-        out.set(left, top, left + width, top + height);
-    }
-
-    /** @return The number of tokens in all of the Tasks on this display. */
-    int numTokens() {
-        int count = 0;
-        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
-            count += mTaskHistory.get(taskNdx).mAppTokens.size();
-        }
-        return count;
-    }
-
-    /** Refer to {@link WindowManagerService#createStack(int, int, int, float)} */
-    TaskStack createStack(int stackId, int relativeStackBoxId, int position, float weight) {
-        TaskStack newStack = null;
-        if (DEBUG_STACK) Slog.d(TAG, "createStack: stackId=" + stackId + " relativeStackBoxId="
-                + relativeStackBoxId + " position=" + position + " weight=" + weight);
-        if (stackId == HOME_STACK_ID) {
-            if (mStackBoxes.size() != 1) {
-                throw new IllegalArgumentException("createStack: HOME_STACK_ID (0) not first.");
-            }
-            newStack = mHomeStack;
-        } else {
-            int stackBoxNdx;
-            for (stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
-                final StackBox box = mStackBoxes.get(stackBoxNdx);
-                if (position == StackBox.TASK_STACK_GOES_OVER
-                        || position == StackBox.TASK_STACK_GOES_UNDER) {
-                    // Position indicates a new box is added at top level only.
-                    if (box.contains(relativeStackBoxId)) {
-                        StackBox newBox = new StackBox(mService, this, null);
-                        newStack = new TaskStack(mService, stackId, this);
-                        newStack.mStackBox = newBox;
-                        newBox.mStack = newStack;
-                        final int offset = position == StackBox.TASK_STACK_GOES_OVER ? 1 : 0;
-                        if (DEBUG_STACK) Slog.d(TAG, "createStack: inserting stack at " +
-                                (stackBoxNdx + offset));
-                        mStackBoxes.add(stackBoxNdx + offset, newBox);
-                        break;
-                    }
-                } else {
-                    // Remaining position values indicate a box must be split.
-                    newStack = box.split(stackId, relativeStackBoxId, position, weight);
-                    if (newStack != null) {
-                        break;
-                    }
-                }
-            }
-            if (stackBoxNdx < 0) {
-                throw new IllegalArgumentException("createStack: stackBoxId " + relativeStackBoxId
-                        + " not found.");
-            }
-        }
-        if (newStack != null) {
-            layoutNeeded = true;
-        }
-        EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId, relativeStackBoxId, position,
-                (int)(weight * 100 + 0.5));
-        return newStack;
-    }
-
-    /** Refer to {@link WindowManagerService#resizeStackBox(int, float)} */
-    boolean resizeStack(int stackBoxId, float weight) {
-        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
-            final StackBox box = mStackBoxes.get(stackBoxNdx);
-            if (box.resize(stackBoxId, weight)) {
-                layoutNeeded = true;
-                return true;
-            }
-        }
-        return false;
-    }
-
-    void addStackBox(StackBox box, boolean toTop) {
-        if (mStackBoxes.size() >= 2) {
-            throw new RuntimeException("addStackBox: Too many toplevel StackBoxes!");
-        }
-        mStackBoxes.add(toTop ? mStackBoxes.size() : 0, box);
-    }
-
-    void removeStackBox(StackBox box) {
-        if (DEBUG_STACK) Slog.d(TAG, "removeStackBox: box=" + box);
-        final TaskStack stack = box.mStack;
-        if (stack != null && stack.mStackId == HOME_STACK_ID) {
-            // Never delete the home stack, even if it is empty.
-            if (DEBUG_STACK) Slog.d(TAG, "removeStackBox: Not deleting home stack.");
-            return;
-        }
-        mStackBoxes.remove(box);
-    }
-
-    StackBoxInfo getStackBoxInfo(StackBox box) {
-        StackBoxInfo info = new StackBoxInfo();
-        info.stackBoxId = box.mStackBoxId;
-        info.weight = box.mWeight;
-        info.vertical = box.mVertical;
-        info.bounds = new Rect(box.mBounds);
-        if (box.mStack != null) {
-            info.stackId = box.mStack.mStackId;
-            // ActivityManagerService will fill in the StackInfo.
-        } else {
-            info.stackId = -1;
-            info.children = new StackBoxInfo[2];
-            info.children[0] = getStackBoxInfo(box.mFirst);
-            info.children[1] = getStackBoxInfo(box.mSecond);
-        }
-        return info;
-    }
-
-    ArrayList<StackBoxInfo> getStackBoxInfos() {
-        ArrayList<StackBoxInfo> list = new ArrayList<StackBoxInfo>();
-        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
-            list.add(getStackBoxInfo(mStackBoxes.get(stackBoxNdx)));
-        }
-        return list;
-    }
-
-    /**
-     * Move the home StackBox to the top or bottom of mStackBoxes. That is the only place
-     * it is allowed to be. This is a nop if the home StackBox is already in the correct position.
-     * @param toTop Move home to the top of mStackBoxes if true, to the bottom if false.
-     * @return true if a change was made, false otherwise.
-     */
-    boolean moveHomeStackBox(boolean toTop) {
-        if (DEBUG_STACK) Slog.d(TAG, "moveHomeStackBox: toTop=" + toTop + " Callers=" +
-                Debug.getCallers(4));
-        EventLog.writeEvent(EventLogTags.WM_HOME_STACK_MOVED, toTop ? 1 : 0);
-        switch (mStackBoxes.size()) {
-            case 0: throw new RuntimeException("moveHomeStackBox: No home StackBox!");
-            case 1: return false; // Only the home StackBox exists.
-            case 2:
-                if (homeOnTop() ^ toTop) {
-                    mStackBoxes.add(mStackBoxes.remove(0));
-                    return true;
-                }
-                return false;
-            default: throw new RuntimeException("moveHomeStackBox: Too many toplevel StackBoxes!");
-        }
-    }
-
-    /**
-     * Propagate the new bounds to all child stack boxes, applying weights as we move down.
-     * @param contentRect The bounds to apply at the top level.
-     */
-    boolean setStackBoxSize(Rect contentRect) {
-        boolean change = false;
-        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
-            change |= mStackBoxes.get(stackBoxNdx).setStackBoxSizes(contentRect, true);
-        }
-        return change;
-    }
-
-    Rect getStackBounds(int stackId) {
-        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
-            Rect bounds = mStackBoxes.get(stackBoxNdx).getStackBounds(stackId);
-            if (bounds != null) {
-                return bounds;
-            }
-        }
-        return null;
-    }
-
-    int stackIdFromPoint(int x, int y) {
-        StackBox topBox = mStackBoxes.get(mStackBoxes.size() - 1);
-        return topBox.stackIdFromPoint(x, y);
-    }
-
-    void setTouchExcludeRegion(TaskStack focusedStack) {
-        mTouchExcludeRegion.set(mBaseDisplayRect);
-        WindowList windows = getWindowList();
-        for (int i = windows.size() - 1; i >= 0; --i) {
-            final WindowState win = windows.get(i);
-            final TaskStack stack = win.getStack();
-            if (win.isVisibleLw() && stack != null && stack != focusedStack) {
-                mTmpRect.set(win.mVisibleFrame);
-                mTmpRect.intersect(win.mVisibleInsets);
-                mTouchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE);
-            }
-        }
-    }
-
-    void switchUserStacks(int oldUserId, int newUserId) {
-        final WindowList windows = getWindowList();
-        for (int i = 0; i < windows.size(); i++) {
-            final WindowState win = windows.get(i);
-            if (win.isHiddenFromUserLocked()) {
-                if (DEBUG_VISIBILITY) Slog.w(TAG, "user changing " + newUserId + " hiding "
-                        + win + ", attrs=" + win.mAttrs.type + ", belonging to "
-                        + win.mOwnerUid);
-                win.hideLw(false);
-            }
-        }
-
-        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
-            mStackBoxes.get(stackBoxNdx).switchUserStacks(newUserId);
-        }
-    }
-
-    void resetAnimationBackgroundAnimator() {
-        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
-            mStackBoxes.get(stackBoxNdx).resetAnimationBackgroundAnimator();
-        }
-    }
-
-    boolean animateDimLayers() {
-        boolean result = false;
-        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
-            result |= mStackBoxes.get(stackBoxNdx).animateDimLayers();
-        }
-        return result;
-    }
-
-    void resetDimming() {
-        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
-            mStackBoxes.get(stackBoxNdx).resetDimming();
-        }
-    }
-
-    boolean isDimming() {
-        boolean result = false;
-        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
-            result |= mStackBoxes.get(stackBoxNdx).isDimming();
-        }
-        return result;
-    }
-
-    void stopDimmingIfNeeded() {
-        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
-            mStackBoxes.get(stackBoxNdx).stopDimmingIfNeeded();
-        }
-    }
-
-    void close() {
-        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
-            mStackBoxes.get(stackBoxNdx).close();
-        }
-    }
-
-    public void dump(String prefix, PrintWriter pw) {
-        pw.print(prefix); pw.print("Display: mDisplayId="); pw.println(mDisplayId);
-        final String subPrefix = "  " + prefix;
-        pw.print(subPrefix); pw.print("init="); pw.print(mInitialDisplayWidth); pw.print("x");
-            pw.print(mInitialDisplayHeight); pw.print(" "); pw.print(mInitialDisplayDensity);
-            pw.print("dpi");
-            if (mInitialDisplayWidth != mBaseDisplayWidth
-                    || mInitialDisplayHeight != mBaseDisplayHeight
-                    || mInitialDisplayDensity != mBaseDisplayDensity) {
-                pw.print(" base=");
-                pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight);
-                pw.print(" "); pw.print(mBaseDisplayDensity); pw.print("dpi");
-            }
-            pw.print(" cur=");
-            pw.print(mDisplayInfo.logicalWidth);
-            pw.print("x"); pw.print(mDisplayInfo.logicalHeight);
-            pw.print(" app=");
-            pw.print(mDisplayInfo.appWidth);
-            pw.print("x"); pw.print(mDisplayInfo.appHeight);
-            pw.print(" rng="); pw.print(mDisplayInfo.smallestNominalAppWidth);
-            pw.print("x"); pw.print(mDisplayInfo.smallestNominalAppHeight);
-            pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth);
-            pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
-            pw.print(subPrefix); pw.print("layoutNeeded="); pw.println(layoutNeeded);
-        for (int boxNdx = 0; boxNdx < mStackBoxes.size(); ++boxNdx) {
-            pw.print(prefix); pw.print("StackBox #"); pw.println(boxNdx);
-            mStackBoxes.get(boxNdx).dump(prefix + "  ", pw);
-        }
-        int ndx = numTokens();
-        if (ndx > 0) {
-            pw.println();
-            pw.println("  Application tokens in Z order:");
-            getTasks();
-            for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
-                AppTokenList tokens = mTaskHistory.get(taskNdx).mAppTokens;
-                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
-                    final AppWindowToken wtoken = tokens.get(tokenNdx);
-                    pw.print("  App #"); pw.print(ndx--);
-                            pw.print(' '); pw.print(wtoken); pw.println(":");
-                    wtoken.dump(pw, "    ");
-                }
-            }
-        }
-        if (mExitingTokens.size() > 0) {
-            pw.println();
-            pw.println("  Exiting tokens:");
-            for (int i=mExitingTokens.size()-1; i>=0; i--) {
-                WindowToken token = mExitingTokens.get(i);
-                pw.print("  Exiting #"); pw.print(i);
-                pw.print(' '); pw.print(token);
-                pw.println(':');
-                token.dump(pw, "    ");
-            }
-        }
-        if (mExitingAppTokens.size() > 0) {
-            pw.println();
-            pw.println("  Exiting application tokens:");
-            for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
-                WindowToken token = mExitingAppTokens.get(i);
-                pw.print("  Exiting App #"); pw.print(i);
-                  pw.print(' '); pw.print(token);
-                  pw.println(':');
-                  token.dump(pw, "    ");
-            }
-        }
-        pw.println();
-    }
-}
diff --git a/services/java/com/android/server/wm/StackBox.java b/services/java/com/android/server/wm/StackBox.java
deleted file mode 100644
index d351925..0000000
--- a/services/java/com/android/server/wm/StackBox.java
+++ /dev/null
@@ -1,414 +0,0 @@
-/*
- * 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.wm;
-
-import android.graphics.Rect;
-import android.util.Slog;
-
-import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
-import static com.android.server.wm.WindowManagerService.DEBUG_STACK;
-import static com.android.server.wm.WindowManagerService.TAG;
-
-import java.io.PrintWriter;
-
-public class StackBox {
-    /** Used with {@link WindowManagerService#createStack}. Dependent on Configuration LTR/RTL. */
-    public static final int TASK_STACK_GOES_BEFORE = 0;
-    /** Used with {@link WindowManagerService#createStack}. Dependent on Configuration LTR/RTL. */
-    public static final int TASK_STACK_GOES_AFTER = 1;
-    /** Used with {@link WindowManagerService#createStack}. Horizontal to left of. */
-    public static final int TASK_STACK_TO_LEFT_OF = 2;
-    /** Used with {@link WindowManagerService#createStack}. Horizontal to right of. */
-    public static final int TASK_STACK_TO_RIGHT_OF = 3;
-    /** Used with {@link WindowManagerService#createStack}. Vertical: lower t/b Rect values. */
-    public static final int TASK_STACK_GOES_ABOVE = 4;
-    /** Used with {@link WindowManagerService#createStack}. Vertical: higher t/b Rect values. */
-    public static final int TASK_STACK_GOES_BELOW = 5;
-    /** Used with {@link WindowManagerService#createStack}. Put on a higher layer on display. */
-    public static final int TASK_STACK_GOES_OVER = 6;
-    /** Used with {@link WindowManagerService#createStack}. Put on a lower layer on display. */
-    public static final int TASK_STACK_GOES_UNDER = 7;
-
-    static int sCurrentBoxId = 0;
-
-    /** Unique id for this box */
-    final int mStackBoxId;
-
-    /** The service */
-    final WindowManagerService mService;
-
-    /** The display this box sits in. */
-    final DisplayContent mDisplayContent;
-
-    /** Non-null indicates this is mFirst or mSecond of a parent StackBox. Null indicates this
-     * is this entire size of mDisplayContent. */
-    StackBox mParent;
-
-    /** First child, this is null exactly when mStack is non-null. */
-    StackBox mFirst;
-
-    /** Second child, this is null exactly when mStack is non-null. */
-    StackBox mSecond;
-
-    /** Stack of Tasks, this is null exactly when mFirst and mSecond are non-null. */
-    TaskStack mStack;
-
-    /** Content limits relative to the DisplayContent this sits in. */
-    Rect mBounds = new Rect();
-
-    /** Relative orientation of mFirst and mSecond. */
-    boolean mVertical;
-
-    /** Fraction of mBounds to devote to mFirst, remainder goes to mSecond */
-    float mWeight;
-
-    /** Dirty flag. Something inside this or some descendant of this has changed. */
-    boolean layoutNeeded;
-
-    /** True if this StackBox sits below the Status Bar. */
-    boolean mUnderStatusBar;
-
-    /** Used to keep from reallocating a temporary Rect for propagating bounds to child boxes */
-    Rect mTmpRect = new Rect();
-
-    StackBox(WindowManagerService service, DisplayContent displayContent, StackBox parent) {
-        synchronized (StackBox.class) {
-            mStackBoxId = sCurrentBoxId++;
-        }
-
-        mService = service;
-        mDisplayContent = displayContent;
-        mParent = parent;
-    }
-
-    /** Propagate #layoutNeeded bottom up. */
-    void makeDirty() {
-        layoutNeeded = true;
-        if (mParent != null) {
-            mParent.makeDirty();
-        }
-    }
-
-    /**
-     * Determine if a particular StackBox is this one or a descendant of this one.
-     * @param stackBoxId The StackBox being searched for.
-     * @return true if the specified StackBox matches this or one of its descendants.
-     */
-    boolean contains(int stackBoxId) {
-        return mStackBoxId == stackBoxId ||
-                (mStack == null &&  (mFirst.contains(stackBoxId) || mSecond.contains(stackBoxId)));
-    }
-
-    /**
-     * Return the stackId of the stack that intersects the passed point.
-     * @param x coordinate of point.
-     * @param y coordinate of point.
-     * @return -1 if point is outside of mBounds, otherwise the stackId of the containing stack.
-     */
-    int stackIdFromPoint(int x, int y) {
-        if (!mBounds.contains(x, y)) {
-            return -1;
-        }
-        if (mStack != null) {
-            return mStack.mStackId;
-        }
-        int stackId = mFirst.stackIdFromPoint(x, y);
-        if (stackId >= 0) {
-            return stackId;
-        }
-        return mSecond.stackIdFromPoint(x, y);
-    }
-
-    /** Determine if this StackBox is the first child or second child.
-     * @return true if this is the first child.
-     */
-    boolean isFirstChild() {
-        return mParent != null && mParent.mFirst == this;
-    }
-
-    /** Returns the bounds of the specified TaskStack if it is contained in this StackBox.
-     * @param stackId the TaskStack to find the bounds of.
-     * @return a new Rect with the bounds of stackId if it is within this StackBox, null otherwise.
-     */
-    Rect getStackBounds(int stackId) {
-        if (mStack != null) {
-            return mStack.mStackId == stackId ? new Rect(mBounds) : null;
-        }
-        Rect bounds = mFirst.getStackBounds(stackId);
-        if (bounds != null) {
-            return bounds;
-        }
-        return mSecond.getStackBounds(stackId);
-    }
-
-    /**
-     * Create a new TaskStack relative to a specified one by splitting the StackBox containing
-     * the specified TaskStack into two children. The size and position each of the new StackBoxes
-     * is determined by the passed parameters.
-     * @param stackId The id of the new TaskStack to create.
-     * @param relativeStackBoxId The id of the StackBox to place the new TaskStack next to.
-     * @param position One of the static TASK_STACK_GOES_xxx positions defined in this class.
-     * @param weight The percentage size of the parent StackBox to devote to the new TaskStack.
-     * @return The new TaskStack.
-     */
-    TaskStack split(int stackId, int relativeStackBoxId, int position, float weight) {
-        if (mStackBoxId != relativeStackBoxId) {
-            // This is not the targeted StackBox.
-            if (mStack != null) {
-                return null;
-            }
-            // Propagate the split to see if the targeted StackBox is in either sub box.
-            TaskStack stack = mFirst.split(stackId, relativeStackBoxId, position, weight);
-            if (stack != null) {
-                return stack;
-            }
-            return mSecond.split(stackId, relativeStackBoxId, position, weight);
-        }
-
-        // Found it!
-        TaskStack stack = new TaskStack(mService, stackId, mDisplayContent);
-        TaskStack firstStack;
-        TaskStack secondStack;
-        if (position == TASK_STACK_GOES_BEFORE) {
-            // TODO: Test Configuration here for LTR/RTL.
-            position = TASK_STACK_TO_LEFT_OF;
-        } else if (position == TASK_STACK_GOES_AFTER) {
-            // TODO: Test Configuration here for LTR/RTL.
-            position = TASK_STACK_TO_RIGHT_OF;
-        }
-        switch (position) {
-            default:
-            case TASK_STACK_TO_LEFT_OF:
-            case TASK_STACK_TO_RIGHT_OF:
-                mVertical = false;
-                if (position == TASK_STACK_TO_LEFT_OF) {
-                    mWeight = weight;
-                    firstStack = stack;
-                    secondStack = mStack;
-                } else {
-                    mWeight = 1.0f - weight;
-                    firstStack = mStack;
-                    secondStack = stack;
-                }
-                break;
-            case TASK_STACK_GOES_ABOVE:
-            case TASK_STACK_GOES_BELOW:
-                mVertical = true;
-                if (position == TASK_STACK_GOES_ABOVE) {
-                    mWeight = weight;
-                    firstStack = stack;
-                    secondStack = mStack;
-                } else {
-                    mWeight = 1.0f - weight;
-                    firstStack = mStack;
-                    secondStack = stack;
-                }
-                break;
-        }
-
-        mFirst = new StackBox(mService, mDisplayContent, this);
-        firstStack.mStackBox = mFirst;
-        mFirst.mStack = firstStack;
-
-        mSecond = new StackBox(mService, mDisplayContent, this);
-        secondStack.mStackBox = mSecond;
-        mSecond.mStack = secondStack;
-
-        mStack = null;
-        return stack;
-    }
-
-    /** Return the stackId of the first mFirst StackBox with a non-null mStack */
-    int getStackId() {
-        if (mStack != null) {
-            return mStack.mStackId;
-        }
-        return mFirst.getStackId();
-    }
-
-    /** Remove this box and propagate its sibling's content up to their parent.
-     * @return The first stackId of the resulting StackBox. */
-    int remove() {
-        mDisplayContent.layoutNeeded = true;
-
-        if (mParent == null) {
-            // This is the top-plane stack.
-            if (DEBUG_STACK) Slog.i(TAG, "StackBox.remove: removing top plane.");
-            mDisplayContent.removeStackBox(this);
-            return HOME_STACK_ID;
-        }
-
-        StackBox sibling = isFirstChild() ? mParent.mSecond : mParent.mFirst;
-        StackBox grandparent = mParent.mParent;
-        sibling.mParent = grandparent;
-        if (grandparent == null) {
-            // mParent is a top-plane stack. Now sibling will be.
-            if (DEBUG_STACK) Slog.i(TAG, "StackBox.remove: grandparent null");
-            mDisplayContent.removeStackBox(mParent);
-            mDisplayContent.addStackBox(sibling, true);
-        } else {
-            if (DEBUG_STACK) Slog.i(TAG, "StackBox.remove: grandparent getting sibling");
-            if (mParent.isFirstChild()) {
-                grandparent.mFirst = sibling;
-            } else {
-                grandparent.mSecond = sibling;
-            }
-        }
-        return sibling.getStackId();
-    }
-
-    boolean resize(int stackBoxId, float weight) {
-        if (mStackBoxId != stackBoxId) {
-            return mStack == null &&
-                    (mFirst.resize(stackBoxId, weight) || mSecond.resize(stackBoxId, weight));
-        }
-        // Don't change weight on topmost stack.
-        if (mParent != null) {
-            mParent.mWeight = isFirstChild() ? weight : 1.0f - weight;
-        }
-        return true;
-    }
-
-    /** If this is a terminal StackBox (contains a TaskStack) set the bounds.
-     * @param bounds The rectangle to set the bounds to.
-     * @param underStatusBar True if the StackBox is directly below the Status Bar.
-     * @return True if the bounds changed, false otherwise. */
-    boolean setStackBoxSizes(Rect bounds, boolean underStatusBar) {
-        boolean change = false;
-        if (mUnderStatusBar != underStatusBar) {
-            change = true;
-            mUnderStatusBar = underStatusBar;
-        }
-        if (mStack != null) {
-            change |= !mBounds.equals(bounds);
-            if (change) {
-                mBounds.set(bounds);
-                mStack.setBounds(bounds, underStatusBar);
-            }
-        } else {
-            mTmpRect.set(bounds);
-            if (mVertical) {
-                final int height = bounds.height();
-                int firstHeight = (int)(height * mWeight);
-                mTmpRect.bottom = bounds.top + firstHeight;
-                change |= mFirst.setStackBoxSizes(mTmpRect, underStatusBar);
-                mTmpRect.top = mTmpRect.bottom;
-                mTmpRect.bottom = bounds.top + height;
-                change |= mSecond.setStackBoxSizes(mTmpRect, false);
-            } else {
-                final int width = bounds.width();
-                int firstWidth = (int)(width * mWeight);
-                mTmpRect.right = bounds.left + firstWidth;
-                change |= mFirst.setStackBoxSizes(mTmpRect, underStatusBar);
-                mTmpRect.left = mTmpRect.right;
-                mTmpRect.right = bounds.left + width;
-                change |= mSecond.setStackBoxSizes(mTmpRect, underStatusBar);
-            }
-        }
-        return change;
-    }
-
-    void resetAnimationBackgroundAnimator() {
-        if (mStack != null) {
-            mStack.resetAnimationBackgroundAnimator();
-            return;
-        }
-        mFirst.resetAnimationBackgroundAnimator();
-        mSecond.resetAnimationBackgroundAnimator();
-    }
-
-    boolean animateDimLayers() {
-        if (mStack != null) {
-            return mStack.animateDimLayers();
-        }
-        boolean result = mFirst.animateDimLayers();
-        result |= mSecond.animateDimLayers();
-        return result;
-    }
-
-    void resetDimming() {
-        if (mStack != null) {
-            mStack.resetDimmingTag();
-            return;
-        }
-        mFirst.resetDimming();
-        mSecond.resetDimming();
-    }
-
-    boolean isDimming() {
-        if (mStack != null) {
-            return mStack.isDimming();
-        }
-        boolean result = mFirst.isDimming();
-        result |= mSecond.isDimming();
-        return result;
-    }
-
-    void stopDimmingIfNeeded() {
-        if (mStack != null) {
-            mStack.stopDimmingIfNeeded();
-            return;
-        }
-        mFirst.stopDimmingIfNeeded();
-        mSecond.stopDimmingIfNeeded();
-    }
-
-    void switchUserStacks(int userId) {
-        if (mStack != null) {
-            mStack.switchUser(userId);
-            return;
-        }
-        mFirst.switchUserStacks(userId);
-        mSecond.switchUserStacks(userId);
-    }
-
-    void close() {
-        if (mStack != null) {
-            mStack.mDimLayer.mDimSurface.destroy();
-            mStack.mAnimationBackgroundSurface.mDimSurface.destroy();
-            return;
-        }
-        mFirst.close();
-        mSecond.close();
-    }
-
-    public void dump(String prefix, PrintWriter pw) {
-        pw.print(prefix); pw.print("mParent="); pw.println(mParent);
-        pw.print(prefix); pw.print("mBounds="); pw.print(mBounds.toShortString());
-            pw.print(" mVertical="); pw.print(mVertical);
-            pw.print(" layoutNeeded="); pw.println(layoutNeeded);
-        if (mFirst != null) {
-            pw.print(prefix); pw.print("mFirst="); pw.println(System.identityHashCode(mFirst));
-            mFirst.dump(prefix + "  ", pw);
-            pw.print(prefix); pw.print("mSecond="); pw.println(System.identityHashCode(mSecond));
-            mSecond.dump(prefix + "  ", pw);
-        } else {
-            pw.print(prefix); pw.print("mStack="); pw.println(mStack);
-            mStack.dump(prefix + "  ", pw);
-        }
-    }
-
-    @Override
-    public String toString() {
-        if (mStack != null) {
-            return "Box{" + hashCode() + " stack=" + mStack.mStackId + "}";
-        }
-        return "Box{" + hashCode() + " parent=" + System.identityHashCode(mParent)
-                + " first=" + System.identityHashCode(mFirst)
-                + " second=" + System.identityHashCode(mSecond) + "}";
-    }
-}
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
deleted file mode 100644
index 98e9b30..0000000
--- a/services/jni/Android.mk
+++ /dev/null
@@ -1,63 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-    com_android_server_AlarmManagerService.cpp \
-    com_android_server_AssetAtlasService.cpp \
-    com_android_server_ConsumerIrService.cpp \
-    com_android_server_input_InputApplicationHandle.cpp \
-    com_android_server_input_InputManagerService.cpp \
-    com_android_server_input_InputWindowHandle.cpp \
-    com_android_server_LightsService.cpp \
-    com_android_server_power_PowerManagerService.cpp \
-    com_android_server_SerialService.cpp \
-    com_android_server_SystemServer.cpp \
-    com_android_server_UsbDeviceManager.cpp \
-    com_android_server_UsbHostManager.cpp \
-    com_android_server_VibratorService.cpp \
-    com_android_server_location_GpsLocationProvider.cpp \
-    com_android_server_location_FlpHardwareProvider.cpp \
-    com_android_server_connectivity_Vpn.cpp \
-    onload.cpp
-
-LOCAL_C_INCLUDES += \
-    $(JNI_H_INCLUDE) \
-    frameworks/base/services \
-    frameworks/base/core/jni \
-    frameworks/native/services \
-    external/skia/include/core \
-    libcore/include \
-    libcore/include/libsuspend \
-	$(call include-path-for, libhardware)/hardware \
-	$(call include-path-for, libhardware_legacy)/hardware_legacy \
-
-LOCAL_SHARED_LIBRARIES := \
-    libandroid_runtime \
-    libandroidfw \
-    libbinder \
-    libcutils \
-    liblog \
-    libhardware \
-    libhardware_legacy \
-    libnativehelper \
-    libutils \
-    libui \
-    libinput \
-    libinputservice \
-    libsensorservice \
-    libskia \
-    libgui \
-    libusbhost \
-    libsuspend \
-    libEGL \
-    libGLESv2
-
-LOCAL_CFLAGS += -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES
-
-ifeq ($(WITH_MALLOC_LEAK_CHECK),true)
-    LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
-endif
-
-LOCAL_MODULE:= libandroid_servers
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
new file mode 100644
index 0000000..852736b
--- /dev/null
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -0,0 +1,690 @@
+/*
+ * 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.print;
+
+import android.Manifest;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.print.IPrintDocumentAdapter;
+import android.print.IPrintJobStateChangeListener;
+import android.print.IPrintManager;
+import android.print.IPrinterDiscoveryObserver;
+import android.print.PrintAttributes;
+import android.print.PrintJobId;
+import android.print.PrintJobInfo;
+import android.print.PrinterId;
+import android.printservice.PrintServiceInfo;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.SparseArray;
+
+import com.android.internal.R;
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.os.BackgroundThread;
+import com.android.server.SystemService;
+import com.android.server.devicepolicy.DevicePolicyManagerService;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * SystemService wrapper for the PrintManager implementation. Publishes
+ * Context.PRINT_SERVICE.
+ * PrintManager implementation is contained within.
+ */
+
+public final class PrintManagerService extends SystemService {
+
+    private PrintManagerImpl mPrintManagerImpl;
+
+    @Override
+    public void onCreate(Context context) {
+        mPrintManagerImpl = new PrintManagerImpl(context);
+    }
+    @Override
+    public void onStart() {
+        publishBinderService(Context.PRINT_SERVICE, mPrintManagerImpl);
+    }
+
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
+            mPrintManagerImpl.systemRunning();
+        }
+    }
+
+    class PrintManagerImpl extends IPrintManager.Stub {
+        private static final char COMPONENT_NAME_SEPARATOR = ':';
+
+        private static final String EXTRA_PRINT_SERVICE_COMPONENT_NAME =
+                "EXTRA_PRINT_SERVICE_COMPONENT_NAME";
+
+        private final Object mLock = new Object();
+
+        private final Context mContext;
+
+        private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
+
+        private int mCurrentUserId = UserHandle.USER_OWNER;
+
+        PrintManagerImpl(Context context) {
+            mContext = context;
+            registerContentObservers();
+            registerBoradcastReceivers();
+        }
+
+        public void systemRunning() {
+            BackgroundThread.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    final UserState userState;
+                    synchronized (mLock) {
+                        userState = getCurrentUserStateLocked();
+                        userState.updateIfNeededLocked();
+                    }
+                    // This is the first time we switch to this user after boot, so
+                    // now is the time to remove obsolete print jobs since they
+                    // are from the last boot and no application would query them.
+                    userState.removeObsoletePrintJobs();
+                }
+            });
+        }
+
+        @Override
+        public Bundle print(String printJobName, IPrintDocumentAdapter adapter,
+                PrintAttributes attributes, String packageName, int appId, int userId) {
+            final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            String resolvedPackageName = resolveCallingPackageNameEnforcingSecurity(packageName);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                return userState.print(printJobName, adapter, attributes,
+                        resolvedPackageName, resolvedAppId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public List<PrintJobInfo> getPrintJobInfos(int appId, int userId) {
+            final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                return userState.getPrintJobInfos(resolvedAppId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId, int userId) {
+            final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                return userState.getPrintJobInfo(printJobId, resolvedAppId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void cancelPrintJob(PrintJobId printJobId, int appId, int userId) {
+            final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                userState.cancelPrintJob(printJobId, resolvedAppId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void restartPrintJob(PrintJobId printJobId, int appId, int userId) {
+            final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                userState.restartPrintJob(printJobId, resolvedAppId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public List<PrintServiceInfo> getEnabledPrintServices(int userId) {
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                return userState.getEnabledPrintServices();
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public List<PrintServiceInfo> getInstalledPrintServices(int userId) {
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                return userState.getInstalledPrintServices();
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
+                int userId) {
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                userState.createPrinterDiscoverySession(observer);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void destroyPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
+                int userId) {
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                userState.destroyPrinterDiscoverySession(observer);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void startPrinterDiscovery(IPrinterDiscoveryObserver observer,
+                List<PrinterId> priorityList, int userId) {
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                userState.startPrinterDiscovery(observer, priorityList);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void stopPrinterDiscovery(IPrinterDiscoveryObserver observer, int userId) {
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                userState.stopPrinterDiscovery(observer);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void validatePrinters(List<PrinterId> printerIds, int userId) {
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                userState.validatePrinters(printerIds);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void startPrinterStateTracking(PrinterId printerId, int userId) {
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                userState.startPrinterStateTracking(printerId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void stopPrinterStateTracking(PrinterId printerId, int userId) {
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                userState.stopPrinterStateTracking(printerId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void addPrintJobStateChangeListener(IPrintJobStateChangeListener listener,
+                int appId, int userId) throws RemoteException {
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                userState.addPrintJobStateChangeListener(listener, resolvedAppId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void removePrintJobStateChangeListener(IPrintJobStateChangeListener listener,
+                int userId) {
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                userState.removePrintJobStateChangeListener(listener);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
+                    != PackageManager.PERMISSION_GRANTED) {
+                pw.println("Permission Denial: can't dump PrintManager from from pid="
+                        + Binder.getCallingPid()
+                        + ", uid=" + Binder.getCallingUid());
+                return;
+            }
+
+            synchronized (mLock) {
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    pw.println("PRINT MANAGER STATE (dumpsys print)");
+                    final int userStateCount = mUserStates.size();
+                    for (int i = 0; i < userStateCount; i++) {
+                        UserState userState = mUserStates.valueAt(i);
+                        userState.dump(fd, pw, "");
+                        pw.println();
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+        }
+
+        private void registerContentObservers() {
+            final Uri enabledPrintServicesUri = Settings.Secure.getUriFor(
+                    Settings.Secure.ENABLED_PRINT_SERVICES);
+
+            ContentObserver observer = new ContentObserver(BackgroundThread.getHandler()) {
+                @Override
+                public void onChange(boolean selfChange, Uri uri) {
+                    if (enabledPrintServicesUri.equals(uri)) {
+                        synchronized (mLock) {
+                            UserState userState = getCurrentUserStateLocked();
+                            userState.updateIfNeededLocked();
+                        }
+                    }
+                }
+            };
+
+            mContext.getContentResolver().registerContentObserver(enabledPrintServicesUri,
+                    false, observer, UserHandle.USER_ALL);
+        }
+
+        private void registerBoradcastReceivers() {
+            PackageMonitor monitor = new PackageMonitor() {
+                @Override
+                public boolean onPackageChanged(String packageName, int uid, String[] components) {
+                    synchronized (mLock) {
+                        UserState userState = getOrCreateUserStateLocked(getChangingUserId());
+                        Iterator<ComponentName> iterator = userState.getEnabledServices()
+                                .iterator();
+                        while (iterator.hasNext()) {
+                            ComponentName componentName = iterator.next();
+                            if (packageName.equals(componentName.getPackageName())) {
+                                userState.updateIfNeededLocked();
+                                return true;
+                            }
+                        }
+                    }
+                    return false;
+                }
+
+                @Override
+                public void onPackageRemoved(String packageName, int uid) {
+                    synchronized (mLock) {
+                        UserState userState = getOrCreateUserStateLocked(getChangingUserId());
+                        Iterator<ComponentName> iterator = userState.getEnabledServices()
+                                .iterator();
+                        while (iterator.hasNext()) {
+                            ComponentName componentName = iterator.next();
+                            if (packageName.equals(componentName.getPackageName())) {
+                                iterator.remove();
+                                persistComponentNamesToSettingLocked(
+                                        Settings.Secure.ENABLED_PRINT_SERVICES,
+                                        userState.getEnabledServices(), getChangingUserId());
+                                userState.updateIfNeededLocked();
+                                return;
+                            }
+                        }
+                    }
+                }
+
+                @Override
+                public boolean onHandleForceStop(Intent intent, String[] stoppedPackages,
+                        int uid, boolean doit) {
+                    synchronized (mLock) {
+                        UserState userState = getOrCreateUserStateLocked(getChangingUserId());
+                        boolean stoppedSomePackages = false;
+                        Iterator<ComponentName> iterator = userState.getEnabledServices()
+                                .iterator();
+                        while (iterator.hasNext()) {
+                            ComponentName componentName = iterator.next();
+                            String componentPackage = componentName.getPackageName();
+                            for (String stoppedPackage : stoppedPackages) {
+                                if (componentPackage.equals(stoppedPackage)) {
+                                    if (!doit) {
+                                        return true;
+                                    }
+                                    stoppedSomePackages = true;
+                                    break;
+                                }
+                            }
+                        }
+                        if (stoppedSomePackages) {
+                            userState.updateIfNeededLocked();
+                        }
+                        return false;
+                    }
+                }
+
+                @Override
+                public void onPackageAdded(String packageName, int uid) {
+                    Intent intent = new Intent(android.printservice.PrintService.SERVICE_INTERFACE);
+                    intent.setPackage(packageName);
+
+                    List<ResolveInfo> installedServices = mContext.getPackageManager()
+                            .queryIntentServicesAsUser(intent, PackageManager.GET_SERVICES,
+                                    getChangingUserId());
+
+                    if (installedServices == null) {
+                        return;
+                    }
+
+                    final int installedServiceCount = installedServices.size();
+                    for (int i = 0; i < installedServiceCount; i++) {
+                        ServiceInfo serviceInfo = installedServices.get(i).serviceInfo;
+                        ComponentName component = new ComponentName(serviceInfo.packageName,
+                                serviceInfo.name);
+                        String label = serviceInfo.loadLabel(mContext.getPackageManager())
+                                .toString();
+                        showEnableInstalledPrintServiceNotification(component, label,
+                                getChangingUserId());
+                    }
+                }
+
+                private void persistComponentNamesToSettingLocked(String settingName,
+                        Set<ComponentName> componentNames, int userId) {
+                    StringBuilder builder = new StringBuilder();
+                    for (ComponentName componentName : componentNames) {
+                        if (builder.length() > 0) {
+                            builder.append(COMPONENT_NAME_SEPARATOR);
+                        }
+                        builder.append(componentName.flattenToShortString());
+                    }
+                    Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                            settingName, builder.toString(), userId);
+                }
+            };
+
+            // package changes
+            monitor.register(mContext, BackgroundThread.getHandler().getLooper(),
+                    UserHandle.ALL, true);
+
+            // user changes
+            IntentFilter intentFilter = new IntentFilter();
+            intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
+            intentFilter.addAction(Intent.ACTION_USER_REMOVED);
+
+            mContext.registerReceiverAsUser(new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    String action = intent.getAction();
+                    if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+                        switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
+                    } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
+                        removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
+                    }
+                }
+            }, UserHandle.ALL, intentFilter, null, BackgroundThread.getHandler());
+        }
+
+        private UserState getCurrentUserStateLocked() {
+            return getOrCreateUserStateLocked(mCurrentUserId);
+        }
+
+        private UserState getOrCreateUserStateLocked(int userId) {
+            UserState userState = mUserStates.get(userId);
+            if (userState == null) {
+                userState = new UserState(mContext, userId, mLock);
+                mUserStates.put(userId, userState);
+            }
+            return userState;
+        }
+
+        private void switchUser(int newUserId) {
+            UserState userState;
+            synchronized (mLock) {
+                if (newUserId == mCurrentUserId) {
+                    return;
+                }
+                mCurrentUserId = newUserId;
+                userState = mUserStates.get(mCurrentUserId);
+                if (userState == null) {
+                    userState = getCurrentUserStateLocked();
+                    userState.updateIfNeededLocked();
+                } else {
+                    userState.updateIfNeededLocked();
+                }
+            }
+            // This is the first time we switch to this user after boot, so
+            // now is the time to remove obsolete print jobs since they
+            // are from the last boot and no application would query them.
+            userState.removeObsoletePrintJobs();
+        }
+
+        private void removeUser(int removedUserId) {
+            synchronized (mLock) {
+                UserState userState = mUserStates.get(removedUserId);
+                if (userState != null) {
+                    userState.destroyLocked();
+                    mUserStates.remove(removedUserId);
+                }
+            }
+        }
+
+        private int resolveCallingAppEnforcingPermissions(int appId) {
+            final int callingUid = Binder.getCallingUid();
+            if (callingUid == 0 || callingUid == Process.SYSTEM_UID
+                    || callingUid == Process.SHELL_UID) {
+                return appId;
+            }
+            final int callingAppId = UserHandle.getAppId(callingUid);
+            if (appId == callingAppId) {
+                return appId;
+            }
+            if (mContext.checkCallingPermission(
+                    "com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS")
+                    != PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException("Call from app " + callingAppId + " as app "
+                        + appId + " without com.android.printspooler.permission"
+                        + ".ACCESS_ALL_PRINT_JOBS");
+            }
+            return appId;
+        }
+
+        private int resolveCallingUserEnforcingPermissions(int userId) {
+            final int callingUid = Binder.getCallingUid();
+            if (callingUid == 0 || callingUid == Process.SYSTEM_UID
+                    || callingUid == Process.SHELL_UID) {
+                return userId;
+            }
+            final int callingUserId = UserHandle.getUserId(callingUid);
+            if (callingUserId == userId) {
+                return userId;
+            }
+            if (mContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+                    != PackageManager.PERMISSION_GRANTED
+                ||  mContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS)
+                    != PackageManager.PERMISSION_GRANTED) {
+                if (userId == UserHandle.USER_CURRENT_OR_SELF) {
+                    return callingUserId;
+                }
+                throw new SecurityException("Call from user " + callingUserId + " as user "
+                    + userId + " without permission INTERACT_ACROSS_USERS or "
+                    + "INTERACT_ACROSS_USERS_FULL not allowed.");
+            }
+            if (userId == UserHandle.USER_CURRENT || userId == UserHandle.USER_CURRENT_OR_SELF) {
+                return mCurrentUserId;
+            }
+            throw new IllegalArgumentException("Calling user can be changed to only "
+                    + "UserHandle.USER_CURRENT or UserHandle.USER_CURRENT_OR_SELF.");
+        }
+
+        private String resolveCallingPackageNameEnforcingSecurity(String packageName) {
+            if (TextUtils.isEmpty(packageName)) {
+                return null;
+            }
+            String[] packages = mContext.getPackageManager().getPackagesForUid(
+                    Binder.getCallingUid());
+            final int packageCount = packages.length;
+            for (int i = 0; i < packageCount; i++) {
+                if (packageName.equals(packages[i])) {
+                    return packageName;
+                }
+            }
+            return null;
+        }
+
+        private void showEnableInstalledPrintServiceNotification(ComponentName component,
+                String label, int userId) {
+            UserHandle userHandle = new UserHandle(userId);
+
+            Intent intent = new Intent(Settings.ACTION_PRINT_SETTINGS);
+            intent.putExtra(EXTRA_PRINT_SERVICE_COMPONENT_NAME, component.flattenToString());
+
+            PendingIntent pendingIntent = PendingIntent.getActivityAsUser(mContext, 0, intent,
+                    PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT, null,
+                    userHandle);
+
+            Notification.Builder builder = new Notification.Builder(mContext)
+                    .setSmallIcon(R.drawable.ic_print)
+                    .setContentTitle(mContext.getString(R.string.print_service_installed_title,
+                            label))
+                    .setContentText(mContext.getString(R.string.print_service_installed_message))
+                    .setContentIntent(pendingIntent)
+                    .setWhen(System.currentTimeMillis())
+                    .setAutoCancel(true)
+                    .setShowWhen(true);
+
+            NotificationManager notificationManager = (NotificationManager) mContext
+                    .getSystemService(Context.NOTIFICATION_SERVICE);
+
+            String notificationTag = getClass().getName() + ":" + component.flattenToString();
+            notificationManager.notifyAsUser(notificationTag, 0, builder.build(),
+                    userHandle);
+        }
+    }
+}
diff --git a/services/java/com/android/server/print/RemotePrintService.java b/services/print/java/com/android/server/print/RemotePrintService.java
similarity index 100%
rename from services/java/com/android/server/print/RemotePrintService.java
rename to services/print/java/com/android/server/print/RemotePrintService.java
diff --git a/services/java/com/android/server/print/RemotePrintSpooler.java b/services/print/java/com/android/server/print/RemotePrintSpooler.java
similarity index 100%
rename from services/java/com/android/server/print/RemotePrintSpooler.java
rename to services/print/java/com/android/server/print/RemotePrintSpooler.java
diff --git a/services/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
similarity index 100%
rename from services/java/com/android/server/print/UserState.java
rename to services/print/java/com/android/server/print/UserState.java
diff --git a/services/print/java/service.mk b/services/print/java/service.mk
new file mode 100644
index 0000000..cba3612
--- /dev/null
+++ b/services/print/java/service.mk
@@ -0,0 +1,11 @@
+# Include only if the service is required
+ifneq ($(findstring print,$(REQUIRED_SERVICES)),)
+
+SUB_DIR := print/java
+
+LOCAL_SRC_FILES += \
+      $(call all-java-files-under,$(SUB_DIR))
+
+#DEFINED_SERVICES += com.android.server.print.PrintManagerService
+
+endif