Merge changes I5d41419a,I763be06c into oc-dev

* changes:
  Introduce android.anim thread in system_server
  Fix thread booster
This commit is contained in:
TreeHugger Robot
2017-04-07 22:05:14 +00:00
committed by Android (Google) Code Review
13 changed files with 133 additions and 45 deletions

View File

@@ -31,7 +31,7 @@ public class SurfaceFlingerVsyncChoreographer {
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 @@ public class SurfaceFlingerVsyncChoreographer {
*/
private long mSurfaceFlingerOffsetMs;
public SurfaceFlingerVsyncChoreographer(Handler handler, Display display) {
public SurfaceFlingerVsyncChoreographer(Handler handler, Display display,
Choreographer choreographer) {
mHandler = handler;
mChoreographer = choreographer;
mSurfaceFlingerOffsetMs = calculateAppSurfaceFlingerVsyncOffsetMs(display);
}

View File

@@ -33,6 +33,7 @@ import android.os.Bundle;
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 @@ public class DividerView extends FrameLayout implements OnTouchListener,
protected void onAttachedToWindow() {
super.onAttachedToWindow();
EventBus.getDefault().register(this);
mSfChoreographer = new SurfaceFlingerVsyncChoreographer(mHandler, getDisplay());
mSfChoreographer = new SurfaceFlingerVsyncChoreographer(mHandler, getDisplay(),
Choreographer.getInstance());
}
@Override

View File

@@ -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;
}
}
}

View File

@@ -17,6 +17,7 @@
package com.android.server;
import android.os.Handler;
import android.os.Process;
import android.os.Trace;
/**
@@ -30,7 +31,9 @@ public final class DisplayThread extends ServiceThread {
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() {

View File

@@ -41,8 +41,8 @@ public class ThreadPriorityBooster {
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++;

View File

@@ -63,6 +63,7 @@ import android.view.DisplayInfo;
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 final class DisplayManagerService extends SystemService {
}
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

View File

@@ -554,7 +554,7 @@ public class AppWindowContainerController
// 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() {

View File

@@ -262,7 +262,8 @@ class TaskPositioner implements DimLayer.DimLayerUser {
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;

View File

@@ -25,7 +25,6 @@ import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_C
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.SurfaceControl;
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 @@ public class WindowAnimator {
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 @@ public class WindowAnimator {
mRemoveReplacedWindows = true;
}
void scheduleAnimation() {
if (!mAnimationScheduled) {
mAnimationScheduled = true;
mChoreographer.postFrameCallback(mAnimationFrameCallback);
}
}
private class DisplayContentsAnimator {
ScreenRotationAnimation mScreenRotationAnimation = null;
}
@@ -374,6 +385,14 @@ public class WindowAnimator {
return mAnimating;
}
boolean isAnimationScheduled() {
return mAnimationScheduled;
}
Choreographer getChoreographer() {
return mChoreographer;
}
void setAnimating(boolean animating) {
mAnimating = animating;
}

View File

@@ -31,6 +31,7 @@ import static android.os.Process.SHELL_UID;
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.ParcelFileDescriptor;
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.SparseIntArray;
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.IInputContext;
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 @@ public class WindowManagerService extends IWindowManager.Stub
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 @@ public class WindowManagerService extends IWindowManager.Stub
// 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 @@ public class WindowManagerService extends IWindowManager.Stub
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 @@ public class WindowManagerService extends IWindowManager.Stub
}
} 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 @@ public class WindowManagerService extends IWindowManager.Stub
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 @@ public class WindowManagerService extends IWindowManager.Stub
/** 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

View File

@@ -30,7 +30,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACT
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 @@ class WindowSurfacePlacer {
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 @@ class WindowSurfacePlacer {
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 @@ class WindowSurfacePlacer {
void requestTraversal() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mService.mH.sendEmptyMessage(DO_TRAVERSAL);
mService.mAnimationHandler.post(mPerformSurfacePlacement);
}
}

View File

@@ -98,11 +98,11 @@ public class AppWindowContainerControllerTests extends WindowTestsBase {
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 @@ public class AppWindowContainerControllerTests extends WindowTestsBase {
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 @@ public class AppWindowContainerControllerTests extends WindowTestsBase {
});
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());
}

View File

@@ -167,8 +167,9 @@ class WindowTestsBase {
/**
* 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) {