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

Commit e0f61dec authored by Winson Chung's avatar Winson Chung
Browse files

Tweak shell thread and clean up some code

- Make shell main thread display priority to match boosted code in
  wm core
- Make shell thread handlers async
- Add tracing and logs for debug builds

Bug: 181979527
Test: atest WMShellUnitTests
Change-Id: Ib3494d77317b24897f5f3738814b5977cd5a2d40
parent 8f02ccf5
Loading
Loading
Loading
Loading
+1 −112
Original line number Diff line number Diff line
@@ -16,26 +16,18 @@

package com.android.systemui.wmshell;

import static android.os.Process.THREAD_PRIORITY_DISPLAY;
import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST;

import android.animation.AnimationHandler;
import android.app.ActivityTaskManager;
import android.content.Context;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.HandlerThread;
import android.view.IWindowManager;
import android.view.WindowManager;

import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.R;
import com.android.systemui.dagger.WMComponent;
import com.android.systemui.dagger.WMSingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.wm.shell.FullscreenTaskListener;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellCommandHandler;
@@ -53,13 +45,11 @@ import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.HandlerExecutor;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.annotations.ChoreographerSfVsync;
import com.android.wm.shell.common.annotations.ShellAnimationThread;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.common.annotations.ShellSplashscreenThread;
@@ -99,110 +89,9 @@ import dagger.Provides;
 * dependencies that are device/form factor SystemUI implementation specific should go into their
 * respective modules (ie. {@link WMShellModule} for handheld, {@link TvWMShellModule} for tv, etc.)
 */
@Module
@Module(includes = WMShellConcurrencyModule.class)
public abstract class WMShellBaseModule {

    /**
     * Returns whether to enable a separate shell thread for the shell features.
     */
    private static boolean enableShellMainThread(Context context) {
        return context.getResources().getBoolean(R.bool.config_enableShellMainThread);
    }

    //
    // Shell Concurrency - Components used for managing threading in the Shell and SysUI
    //

    /**
     * Provide a SysUI main-thread Executor.
     */
    @WMSingleton
    @Provides
    @Main
    public static ShellExecutor provideSysUIMainExecutor(@Main Handler sysuiMainHandler) {
        return new HandlerExecutor(sysuiMainHandler);
    }

    /**
     * Shell main-thread Handler, don't use this unless really necessary (ie. need to dedupe
     * multiple types of messages, etc.)
     */
    @WMSingleton
    @Provides
    @ShellMainThread
    public static Handler provideShellMainHandler(Context context, @Main Handler sysuiMainHandler) {
        if (enableShellMainThread(context)) {
             HandlerThread mainThread = new HandlerThread("wmshell.main");
             mainThread.start();
             return mainThread.getThreadHandler();
        }
        return sysuiMainHandler;
    }

    /**
     * Provide a Shell main-thread Executor.
     */
    @WMSingleton
    @Provides
    @ShellMainThread
    public static ShellExecutor provideShellMainExecutor(Context context,
            @ShellMainThread Handler mainHandler, @Main ShellExecutor sysuiMainExecutor) {
        if (enableShellMainThread(context)) {
            return new HandlerExecutor(mainHandler);
        }
        return sysuiMainExecutor;
    }

    /**
     * Provide a Shell animation-thread Executor.
     */
    @WMSingleton
    @Provides
    @ShellAnimationThread
    public static ShellExecutor provideShellAnimationExecutor() {
         HandlerThread shellAnimationThread = new HandlerThread("wmshell.anim",
                 THREAD_PRIORITY_DISPLAY);
         shellAnimationThread.start();
         return new HandlerExecutor(shellAnimationThread.getThreadHandler());
    }

    /**
     * Provides a Shell splashscreen-thread Executor
     */
    @WMSingleton
    @Provides
    @ShellSplashscreenThread
    public static ShellExecutor provideSplashScreenExecutor() {
        HandlerThread shellSplashscreenThread = new HandlerThread("wmshell.splashscreen",
                THREAD_PRIORITY_TOP_APP_BOOST);
        shellSplashscreenThread.start();
        return new HandlerExecutor(shellSplashscreenThread.getThreadHandler());
    }

    /**
     * Provide a Shell main-thread AnimationHandler.  The AnimationHandler can be set on
     * {@link android.animation.ValueAnimator}s and will ensure that the animation will run on
     * the Shell main-thread with the SF vsync.
     */
    @WMSingleton
    @Provides
    @ChoreographerSfVsync
    public static AnimationHandler provideShellMainExecutorSfVsyncAnimationHandler(
            @ShellMainThread ShellExecutor mainExecutor) {
        try {
            AnimationHandler handler = new AnimationHandler();
            mainExecutor.executeBlocking(() -> {
                // This is called on the animation thread since it calls
                // Choreographer.getSfInstance() which returns a thread-local Choreographer instance
                // that uses the SF vsync
                handler.setProvider(new SfVsyncFrameCallbackProvider());
            });
            return handler;
        } catch (InterruptedException e) {
            throw new RuntimeException("Failed to initialize SfVsync animation handler in 1s", e);
        }
    }

    //
    // Internal common - Components used internally by multiple shell features
    //
+163 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.systemui.wmshell;

import static android.os.Process.THREAD_PRIORITY_DISPLAY;
import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST;

import android.animation.AnimationHandler;
import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Trace;

import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.systemui.R;
import com.android.systemui.dagger.WMSingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.wm.shell.common.HandlerExecutor;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.annotations.ChoreographerSfVsync;
import com.android.wm.shell.common.annotations.ShellAnimationThread;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.common.annotations.ShellSplashscreenThread;

import dagger.Module;
import dagger.Provides;

/**
 * Provides basic concurrency-related dependencies from {@link com.android.wm.shell}, these
 * dependencies are only accessible from components within the WM subcomponent.
 */
@Module
public abstract class WMShellConcurrencyModule {

    private static final int MSGQ_SLOW_DELIVERY_THRESHOLD_MS = 30;
    private static final int MSGQ_SLOW_DISPATCH_THRESHOLD_MS = 30;

    /**
     * Returns whether to enable a separate shell thread for the shell features.
     */
    private static boolean enableShellMainThread(Context context) {
        return context.getResources().getBoolean(R.bool.config_enableShellMainThread);
    }

    //
    // Shell Concurrency - Components used for managing threading in the Shell and SysUI
    //

    /**
     * Provide a SysUI main-thread Executor.
     */
    @WMSingleton
    @Provides
    @Main
    public static ShellExecutor provideSysUIMainExecutor(@Main Handler sysuiMainHandler) {
        return new HandlerExecutor(sysuiMainHandler);
    }

    /**
     * Shell main-thread Handler, don't use this unless really necessary (ie. need to dedupe
     * multiple types of messages, etc.)
     */
    @WMSingleton
    @Provides
    @ShellMainThread
    public static Handler provideShellMainHandler(Context context, @Main Handler sysuiMainHandler) {
        if (enableShellMainThread(context)) {
             HandlerThread mainThread = new HandlerThread("wmshell.main", THREAD_PRIORITY_DISPLAY);
             mainThread.start();
             if (Build.IS_DEBUGGABLE) {
                 mainThread.getLooper().setTraceTag(Trace.TRACE_TAG_WINDOW_MANAGER);
                 mainThread.getLooper().setSlowLogThresholdMs(MSGQ_SLOW_DISPATCH_THRESHOLD_MS,
                         MSGQ_SLOW_DELIVERY_THRESHOLD_MS);
             }
             return Handler.createAsync(mainThread.getLooper());
        }
        return sysuiMainHandler;
    }

    /**
     * Provide a Shell main-thread Executor.
     */
    @WMSingleton
    @Provides
    @ShellMainThread
    public static ShellExecutor provideShellMainExecutor(Context context,
            @ShellMainThread Handler mainHandler, @Main ShellExecutor sysuiMainExecutor) {
        if (enableShellMainThread(context)) {
            return new HandlerExecutor(mainHandler);
        }
        return sysuiMainExecutor;
    }

    /**
     * Provide a Shell animation-thread Executor.
     */
    @WMSingleton
    @Provides
    @ShellAnimationThread
    public static ShellExecutor provideShellAnimationExecutor() {
         HandlerThread shellAnimationThread = new HandlerThread("wmshell.anim",
                 THREAD_PRIORITY_DISPLAY);
         shellAnimationThread.start();
        if (Build.IS_DEBUGGABLE) {
            shellAnimationThread.getLooper().setTraceTag(Trace.TRACE_TAG_WINDOW_MANAGER);
            shellAnimationThread.getLooper().setSlowLogThresholdMs(MSGQ_SLOW_DISPATCH_THRESHOLD_MS,
                    MSGQ_SLOW_DELIVERY_THRESHOLD_MS);
        }
         return new HandlerExecutor(Handler.createAsync(shellAnimationThread.getLooper()));
    }

    /**
     * Provides a Shell splashscreen-thread Executor
     */
    @WMSingleton
    @Provides
    @ShellSplashscreenThread
    public static ShellExecutor provideSplashScreenExecutor() {
        HandlerThread shellSplashscreenThread = new HandlerThread("wmshell.splashscreen",
                THREAD_PRIORITY_TOP_APP_BOOST);
        shellSplashscreenThread.start();
        return new HandlerExecutor(shellSplashscreenThread.getThreadHandler());
    }

    /**
     * Provide a Shell main-thread AnimationHandler.  The AnimationHandler can be set on
     * {@link android.animation.ValueAnimator}s and will ensure that the animation will run on
     * the Shell main-thread with the SF vsync.
     */
    @WMSingleton
    @Provides
    @ChoreographerSfVsync
    public static AnimationHandler provideShellMainExecutorSfVsyncAnimationHandler(
            @ShellMainThread ShellExecutor mainExecutor) {
        try {
            AnimationHandler handler = new AnimationHandler();
            mainExecutor.executeBlocking(() -> {
                // This is called on the animation thread since it calls
                // Choreographer.getSfInstance() which returns a thread-local Choreographer instance
                // that uses the SF vsync
                handler.setProvider(new SfVsyncFrameCallbackProvider());
            });
            return handler;
        } catch (InterruptedException e) {
            throw new RuntimeException("Failed to initialize SfVsync animation handler in 1s", e);
        }
    }
}