Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ed7993b5 authored by Jorim Jaggi's avatar Jorim Jaggi
Browse files

Introduce android.anim thread in system_server

We create a new thread on which everything is running that
directly impacts window animations, i.e. layout, anim tick and
starting window creation. This is such that any work on
android.display can not lead to jank in the window animation,
specifically lock contention on activity manager lock that blocks
callbacks from android.display into AM can not lead to window
animation jank.

Test: Run animation, take systrace, make sure animation is on
android.anim
Test: AppWindowContainerControllerTestTest: AppWindowContainerControllerTestss
Fixes: 36792959

Change-Id: I5d41419a709b7984724e7053a3afdcc1ffe1aaa2
parent 5515b12b
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -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);
    }

+3 −1
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
/*
 * 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;
        }
    }
}
+4 −1
Original line number Diff line number Diff line
@@ -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() {
+8 −7
Original line number Diff line number Diff line
@@ -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
Loading