Merge changes I5d41419a,I763be06c into oc-dev
* changes: Introduce android.anim thread in system_server Fix thread booster
This commit is contained in:
committed by
Android (Google) Code Review
commit
bc4bd823d9
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
58
services/core/java/com/android/server/AnimationThread.java
Normal file
58
services/core/java/com/android/server/AnimationThread.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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() {
|
||||
|
||||
@@ -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++;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user