Merge changes I5d41419a,I763be06c into oc-dev

* changes:
  Introduce android.anim thread in system_server
  Fix thread booster
diff --git a/core/java/com/android/internal/view/SurfaceFlingerVsyncChoreographer.java b/core/java/com/android/internal/view/SurfaceFlingerVsyncChoreographer.java
index e40090f..924b3f7 100644
--- a/core/java/com/android/internal/view/SurfaceFlingerVsyncChoreographer.java
+++ b/core/java/com/android/internal/view/SurfaceFlingerVsyncChoreographer.java
@@ -31,7 +31,7 @@
     private static final long ONE_S_IN_NS = ONE_MS_IN_NS * 1000;
 
     private final Handler mHandler;
-    private final Choreographer mChoreographer = Choreographer.getInstance();
+    private final Choreographer mChoreographer;
 
     /**
      * The offset between vsync-app and vsync-surfaceflinger. See
@@ -39,8 +39,10 @@
      */
     private long mSurfaceFlingerOffsetMs;
 
-    public SurfaceFlingerVsyncChoreographer(Handler handler, Display display) {
+    public SurfaceFlingerVsyncChoreographer(Handler handler, Display display,
+            Choreographer choreographer) {
         mHandler = handler;
+        mChoreographer = choreographer;
         mSurfaceFlingerOffsetMs = calculateAppSurfaceFlingerVsyncOffsetMs(display);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 0ee3e19..c48ecdb 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -33,6 +33,7 @@
 import android.os.Handler;
 import android.os.Message;
 import android.util.AttributeSet;
+import android.view.Choreographer;
 import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.GestureDetector;
@@ -312,7 +313,8 @@
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         EventBus.getDefault().register(this);
-        mSfChoreographer = new SurfaceFlingerVsyncChoreographer(mHandler, getDisplay());
+        mSfChoreographer = new SurfaceFlingerVsyncChoreographer(mHandler, getDisplay(),
+                Choreographer.getInstance());
     }
 
     @Override
diff --git a/services/core/java/com/android/server/AnimationThread.java b/services/core/java/com/android/server/AnimationThread.java
new file mode 100644
index 0000000..08392b0
--- /dev/null
+++ b/services/core/java/com/android/server/AnimationThread.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2017 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 static android.os.Process.THREAD_PRIORITY_DISPLAY;
+
+import android.os.Handler;
+import android.os.Trace;
+
+/**
+ * Thread for handling all window animations, or anything that's directly impacting animations like
+ * starting windows or traversals.
+ */
+public final class AnimationThread extends ServiceThread {
+    private static AnimationThread sInstance;
+    private static Handler sHandler;
+
+    private AnimationThread() {
+        super("android.anim", THREAD_PRIORITY_DISPLAY, false /*allowIo*/);
+    }
+
+    private static void ensureThreadLocked() {
+        if (sInstance == null) {
+            sInstance = new AnimationThread();
+            sInstance.start();
+            sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_WINDOW_MANAGER);
+            sHandler = new Handler(sInstance.getLooper());
+        }
+    }
+
+    public static AnimationThread get() {
+        synchronized (AnimationThread.class) {
+            ensureThreadLocked();
+            return sInstance;
+        }
+    }
+
+    public static Handler getHandler() {
+        synchronized (AnimationThread.class) {
+            ensureThreadLocked();
+            return sHandler;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/DisplayThread.java b/services/core/java/com/android/server/DisplayThread.java
index 9ef0259..cad2a61 100644
--- a/services/core/java/com/android/server/DisplayThread.java
+++ b/services/core/java/com/android/server/DisplayThread.java
@@ -17,6 +17,7 @@
 package com.android.server;
 
 import android.os.Handler;
+import android.os.Process;
 import android.os.Trace;
 
 /**
@@ -30,7 +31,9 @@
     private static Handler sHandler;
 
     private DisplayThread() {
-        super("android.display", android.os.Process.THREAD_PRIORITY_DISPLAY, false /*allowIo*/);
+        // DisplayThread runs important stuff, but these are not as important as things running in
+        // AnimationThread. Thus, set the priority to one lower.
+        super("android.display", Process.THREAD_PRIORITY_DISPLAY + 1, false /*allowIo*/);
     }
 
     private static void ensureThreadLocked() {
diff --git a/services/core/java/com/android/server/ThreadPriorityBooster.java b/services/core/java/com/android/server/ThreadPriorityBooster.java
index 17965d0..31726ad 100644
--- a/services/core/java/com/android/server/ThreadPriorityBooster.java
+++ b/services/core/java/com/android/server/ThreadPriorityBooster.java
@@ -41,8 +41,8 @@
         final int tid = Process.myTid();
         final int prevPriority = Process.getThreadPriority(tid);
         PriorityState state = mThreadState.get();
+        state.prevPriority = prevPriority;
         if (state.regionCounter == 0 && prevPriority > mBoostToPriority) {
-            state.prevPriority = prevPriority;
             Process.setThreadPriority(tid, mBoostToPriority);
         }
         state.regionCounter++;
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index d83676b..2082958 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -63,6 +63,7 @@
 import android.view.Surface;
 import android.view.WindowManagerInternal;
 
+import com.android.server.AnimationThread;
 import com.android.server.DisplayThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
@@ -257,13 +258,13 @@
     }
 
     public void setupSchedulerPolicies() {
-	/*
-	 * android.display is critical to user experience and we should
-	 * make sure it is not in the default foregroup groups, add it to
-	 * top-app to make sure it uses all the cores and scheduling
-	 * settings for top-app when it runs.
-	 */
-	Process.setThreadGroupAndCpuset(DisplayThread.get().getThreadId(), Process.THREAD_GROUP_TOP_APP);
+        // android.display and android.anim is critical to user experience and we should make sure
+        // it is not in the default foregroup groups, add it to top-app to make sure it uses all the
+        // cores and scheduling settings for top-app when it runs.
+        Process.setThreadGroupAndCpuset(DisplayThread.get().getThreadId(),
+                Process.THREAD_GROUP_TOP_APP);
+        Process.setThreadGroupAndCpuset(AnimationThread.get().getThreadId(),
+                Process.THREAD_GROUP_TOP_APP);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
index 4b4be40..a39131c 100644
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -554,7 +554,7 @@
         // want to process the message ASAP, before any other queued
         // messages.
         if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Enqueueing ADD_STARTING");
-        mHandler.postAtFrontOfQueue(mAddStartingWindow);
+        mService.mAnimationHandler.postAtFrontOfQueue(mAddStartingWindow);
     }
 
     private boolean createSnapshot() {
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 53c24e1..0c68e2c 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -262,7 +262,8 @@
         mService.mInputManager.registerInputChannel(mServerChannel, null);
 
         mInputEventReceiver = new WindowPositionerEventReceiver(
-                mClientChannel, mService.mH.getLooper(), mService.mChoreographer);
+                mClientChannel, mService.mAnimationHandler.getLooper(),
+                mService.mAnimator.getChoreographer());
 
         mDragApplicationHandle = new InputApplicationHandle(null);
         mDragApplicationHandle.name = TAG;
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 57eaa2b..1367a06 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -25,7 +25,6 @@
 import static com.android.server.wm.WindowSurfacePlacer.SET_UPDATE_ROTATION;
 
 import android.content.Context;
-import android.os.Handler;
 import android.os.Trace;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -35,7 +34,7 @@
 import android.view.WindowManagerPolicy;
 
 import com.android.internal.view.SurfaceFlingerVsyncChoreographer;
-import com.android.server.DisplayThread;
+import com.android.server.AnimationThread;
 
 import java.io.PrintWriter;
 
@@ -87,20 +86,25 @@
     private final Runnable mAnimationTick;
     private final SurfaceFlingerVsyncChoreographer mSfChoreographer;
 
+    private Choreographer mChoreographer;
+    private boolean mAnimationScheduled;
+
+
     WindowAnimator(final WindowManagerService service) {
         mService = service;
         mContext = service.mContext;
         mPolicy = service.mPolicy;
         mWindowPlacerLocked = service.mWindowPlacerLocked;
-        final Handler handler = DisplayThread.getHandler();
+        AnimationThread.getHandler().runWithScissors(
+                () -> mChoreographer = Choreographer.getInstance(), 0 /* timeout */);
 
         // TODO: Multi-display: If displays have different vsync tick, have a separate tick per
         // display.
-        mSfChoreographer = new SurfaceFlingerVsyncChoreographer(handler,
-                mService.getDefaultDisplayContentLocked().getDisplay());
+        mSfChoreographer = new SurfaceFlingerVsyncChoreographer(AnimationThread.getHandler(),
+                mService.getDefaultDisplayContentLocked().getDisplay(), mChoreographer);
         mAnimationTick = () -> {
             synchronized (mService.mWindowMap) {
-                mService.mAnimationScheduled = false;
+                mAnimationScheduled = false;
                 animateLocked(mCurrentFrameTime);
             }
         };
@@ -366,6 +370,13 @@
         mRemoveReplacedWindows = true;
     }
 
+    void scheduleAnimation() {
+        if (!mAnimationScheduled) {
+            mAnimationScheduled = true;
+            mChoreographer.postFrameCallback(mAnimationFrameCallback);
+        }
+    }
+
     private class DisplayContentsAnimator {
         ScreenRotationAnimation mScreenRotationAnimation = null;
     }
@@ -374,6 +385,14 @@
         return mAnimating;
     }
 
+    boolean isAnimationScheduled() {
+        return mAnimationScheduled;
+    }
+
+    Choreographer getChoreographer() {
+        return mChoreographer;
+    }
+
     void setAnimating(boolean animating) {
         mAnimating = animating;
     }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 843abdc..0f4707e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -31,6 +31,7 @@
 import static android.os.Process.SYSTEM_UID;
 import static android.os.Process.THREAD_PRIORITY_DISPLAY;
 import static android.os.Process.myPid;
+import static android.os.Process.myTid;
 import static android.os.UserHandle.USER_NULL;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.DOCKED_INVALID;
@@ -147,6 +148,7 @@
 import android.os.PowerManager;
 import android.os.PowerManagerInternal;
 import android.os.PowerSaveState;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.StrictMode;
@@ -169,7 +171,6 @@
 import android.util.TimeUtils;
 import android.util.TypedValue;
 import android.view.AppTransitionAnimationSpec;
-import android.view.Choreographer;
 import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.Gravity;
@@ -218,6 +219,7 @@
 import com.android.internal.view.IInputMethodClient;
 import com.android.internal.view.IInputMethodManager;
 import com.android.internal.view.WindowManagerPolicyThread;
+import com.android.server.AnimationThread;
 import com.android.server.DisplayThread;
 import com.android.server.EventLogTags;
 import com.android.server.FgThread;
@@ -604,7 +606,12 @@
 
     final H mH = new H();
 
-    final Choreographer mChoreographer = Choreographer.getInstance();
+    /**
+     * Handler for things to run that have direct impact on an animation, i.e. animation tick,
+     * layout, starting window creation, whereas {@link H} runs things that are still important, but
+     * not as critical.
+     */
+    final Handler mAnimationHandler = new Handler(AnimationThread.getHandler().getLooper());
 
     WindowState mCurrentFocus = null;
     WindowState mLastFocus = null;
@@ -711,8 +718,6 @@
     // For frozen screen animations.
     private int mExitAnimId, mEnterAnimId;
 
-    boolean mAnimationScheduled;
-
     /** Skip repeated AppWindowTokens initialization. Note that AppWindowsToken's version of this
      * is a long initialized to Long.MIN_VALUE so that it doesn't match this value on startup. */
     int mTransactionSequence;
@@ -4648,7 +4653,6 @@
     final class H extends android.os.Handler {
         public static final int REPORT_FOCUS_CHANGE = 2;
         public static final int REPORT_LOSING_FOCUS = 3;
-        public static final int DO_TRAVERSAL = 4;
         public static final int WINDOW_FREEZE_TIMEOUT = 11;
 
         public static final int APP_TRANSITION_TIMEOUT = 13;
@@ -4778,12 +4782,6 @@
                     }
                 } break;
 
-                case DO_TRAVERSAL: {
-                    synchronized(mWindowMap) {
-                        mWindowPlacerLocked.performSurfacePlacement();
-                    }
-                } break;
-
                 case WINDOW_FREEZE_TIMEOUT: {
                     // TODO(multidisplay): Can non-default displays rotate?
                     synchronized (mWindowMap) {
@@ -4852,7 +4850,7 @@
                     synchronized (mWindowMap) {
                         // Since we're holding both mWindowMap and mAnimator we don't need to
                         // hold mAnimator.mLayoutToAnim.
-                        if (mAnimator.isAnimating() || mAnimationScheduled) {
+                        if (mAnimator.isAnimating() || mAnimator.isAnimationScheduled()) {
                             // If we are animating, don't do the gc now but
                             // delay a bit so we don't interrupt the animation.
                             sendEmptyMessageDelayed(H.FORCE_GC, 2000);
@@ -5747,10 +5745,7 @@
 
     /** Note that Locked in this case is on mLayoutToAnim */
     void scheduleAnimationLocked() {
-        if (!mAnimationScheduled) {
-            mAnimationScheduled = true;
-            mChoreographer.postFrameCallback(mAnimator.mAnimationFrameCallback);
-        }
+        mAnimator.scheduleAnimation();
     }
 
     // TODO: Move to DisplayContent
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index ee2d5de..ddd1ca5 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -30,7 +30,6 @@
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.WindowManagerService.H.DO_TRAVERSAL;
 import static com.android.server.wm.WindowManagerService.H.NOTIFY_APP_TRANSITION_STARTING;
 import static com.android.server.wm.WindowManagerService.H.REPORT_WINDOWS_CHANGE;
 import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
@@ -97,9 +96,16 @@
     private final ArrayList<SurfaceControl> mPendingDestroyingSurfaces = new ArrayList<>();
     private final SparseIntArray mTempTransitionReasons = new SparseIntArray();
 
+    private final Runnable mPerformSurfacePlacement;
+
     public WindowSurfacePlacer(WindowManagerService service) {
         mService = service;
         mWallpaperControllerLocked = mService.mRoot.mWallpaperController;
+        mPerformSurfacePlacement = () -> {
+            synchronized (mService.mWindowMap) {
+                performSurfacePlacement();
+            }
+        };
     }
 
     /**
@@ -131,7 +137,7 @@
         do {
             mTraversalScheduled = false;
             performSurfacePlacementLoop();
-            mService.mH.removeMessages(DO_TRAVERSAL);
+            mService.mAnimationHandler.removeCallbacks(mPerformSurfacePlacement);
             loopCount--;
         } while (mTraversalScheduled && loopCount > 0);
         mService.mRoot.mWallpaperActionPending = false;
@@ -735,7 +741,7 @@
     void requestTraversal() {
         if (!mTraversalScheduled) {
             mTraversalScheduled = true;
-            mService.mH.sendEmptyMessage(DO_TRAVERSAL);
+            mService.mAnimationHandler.post(mPerformSurfacePlacement);
         }
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
index 25004de..3c8bf20 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
@@ -98,11 +98,11 @@
                 createAppWindowController();
         controller.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
                 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false);
-        waitUntilHandlerIdle();
+        waitUntilHandlersIdle();
         final AppWindowToken atoken = controller.getAppWindowToken();
         assertHasStartingWindow(atoken);
         controller.removeStartingWindow();
-        waitUntilHandlerIdle();
+        waitUntilHandlersIdle();
         assertNoStartingWindow(atoken);
     }
 
@@ -114,11 +114,11 @@
                 createAppWindowController();
         controller1.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
                 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false);
-        waitUntilHandlerIdle();
+        waitUntilHandlersIdle();
         controller2.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
                 android.R.style.Theme, null, "Test", 0, 0, 0, 0, controller1.mToken.asBinder(),
                 true, true, false);
-        waitUntilHandlerIdle();
+        waitUntilHandlersIdle();
         assertNoStartingWindow(controller1.getAppWindowToken());
         assertHasStartingWindow(controller2.getAppWindowToken());
     }
@@ -138,7 +138,7 @@
         });
         controller1.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
                 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false);
-        waitUntilHandlerIdle();
+        waitUntilHandlersIdle();
         assertNoStartingWindow(controller1.getAppWindowToken());
         assertHasStartingWindow(controller2.getAppWindowToken());
     }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index eaf4ac4..218af73 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -167,8 +167,9 @@
     /**
      * Waits until the main handler for WM has processed all messages.
      */
-    void waitUntilHandlerIdle() {
+    void waitUntilHandlersIdle() {
         sWm.mH.runWithScissors(() -> { }, 0);
+        sWm.mAnimationHandler.runWithScissors(() -> { }, 0);
     }
 
     private static WindowToken createWindowToken(DisplayContent dc, int stackId, int type) {