1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.wmshell; 18 19 import static android.os.Process.THREAD_PRIORITY_DISPLAY; 20 import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST; 21 22 import android.animation.AnimationHandler; 23 import android.content.Context; 24 import android.os.Build; 25 import android.os.Handler; 26 import android.os.HandlerThread; 27 import android.os.Trace; 28 29 import com.android.internal.graphics.SfVsyncFrameCallbackProvider; 30 import com.android.systemui.R; 31 import com.android.systemui.dagger.WMSingleton; 32 import com.android.systemui.dagger.qualifiers.Main; 33 import com.android.wm.shell.common.HandlerExecutor; 34 import com.android.wm.shell.common.ShellExecutor; 35 import com.android.wm.shell.common.annotations.ChoreographerSfVsync; 36 import com.android.wm.shell.common.annotations.ShellAnimationThread; 37 import com.android.wm.shell.common.annotations.ShellMainThread; 38 import com.android.wm.shell.common.annotations.ShellSplashscreenThread; 39 40 import dagger.Module; 41 import dagger.Provides; 42 43 /** 44 * Provides basic concurrency-related dependencies from {@link com.android.wm.shell}, these 45 * dependencies are only accessible from components within the WM subcomponent. 46 */ 47 @Module 48 public abstract class WMShellConcurrencyModule { 49 50 private static final int MSGQ_SLOW_DELIVERY_THRESHOLD_MS = 30; 51 private static final int MSGQ_SLOW_DISPATCH_THRESHOLD_MS = 30; 52 53 /** 54 * Returns whether to enable a separate shell thread for the shell features. 55 */ enableShellMainThread(Context context)56 private static boolean enableShellMainThread(Context context) { 57 return context.getResources().getBoolean(R.bool.config_enableShellMainThread); 58 } 59 60 // 61 // Shell Concurrency - Components used for managing threading in the Shell and SysUI 62 // 63 64 /** 65 * Provide a SysUI main-thread Executor. 66 */ 67 @WMSingleton 68 @Provides 69 @Main provideSysUIMainExecutor(@ain Handler sysuiMainHandler)70 public static ShellExecutor provideSysUIMainExecutor(@Main Handler sysuiMainHandler) { 71 return new HandlerExecutor(sysuiMainHandler); 72 } 73 74 /** 75 * Shell main-thread Handler, don't use this unless really necessary (ie. need to dedupe 76 * multiple types of messages, etc.) 77 */ 78 @WMSingleton 79 @Provides 80 @ShellMainThread provideShellMainHandler(Context context, @Main Handler sysuiMainHandler)81 public static Handler provideShellMainHandler(Context context, @Main Handler sysuiMainHandler) { 82 if (enableShellMainThread(context)) { 83 HandlerThread mainThread = new HandlerThread("wmshell.main", THREAD_PRIORITY_DISPLAY); 84 mainThread.start(); 85 if (Build.IS_DEBUGGABLE) { 86 mainThread.getLooper().setTraceTag(Trace.TRACE_TAG_WINDOW_MANAGER); 87 mainThread.getLooper().setSlowLogThresholdMs(MSGQ_SLOW_DISPATCH_THRESHOLD_MS, 88 MSGQ_SLOW_DELIVERY_THRESHOLD_MS); 89 } 90 return Handler.createAsync(mainThread.getLooper()); 91 } 92 return sysuiMainHandler; 93 } 94 95 /** 96 * Provide a Shell main-thread Executor. 97 */ 98 @WMSingleton 99 @Provides 100 @ShellMainThread provideShellMainExecutor(Context context, @ShellMainThread Handler mainHandler, @Main ShellExecutor sysuiMainExecutor)101 public static ShellExecutor provideShellMainExecutor(Context context, 102 @ShellMainThread Handler mainHandler, @Main ShellExecutor sysuiMainExecutor) { 103 if (enableShellMainThread(context)) { 104 return new HandlerExecutor(mainHandler); 105 } 106 return sysuiMainExecutor; 107 } 108 109 /** 110 * Provide a Shell animation-thread Executor. 111 */ 112 @WMSingleton 113 @Provides 114 @ShellAnimationThread provideShellAnimationExecutor()115 public static ShellExecutor provideShellAnimationExecutor() { 116 HandlerThread shellAnimationThread = new HandlerThread("wmshell.anim", 117 THREAD_PRIORITY_DISPLAY); 118 shellAnimationThread.start(); 119 if (Build.IS_DEBUGGABLE) { 120 shellAnimationThread.getLooper().setTraceTag(Trace.TRACE_TAG_WINDOW_MANAGER); 121 shellAnimationThread.getLooper().setSlowLogThresholdMs(MSGQ_SLOW_DISPATCH_THRESHOLD_MS, 122 MSGQ_SLOW_DELIVERY_THRESHOLD_MS); 123 } 124 return new HandlerExecutor(Handler.createAsync(shellAnimationThread.getLooper())); 125 } 126 127 /** 128 * Provides a Shell splashscreen-thread Executor 129 */ 130 @WMSingleton 131 @Provides 132 @ShellSplashscreenThread provideSplashScreenExecutor()133 public static ShellExecutor provideSplashScreenExecutor() { 134 HandlerThread shellSplashscreenThread = new HandlerThread("wmshell.splashscreen", 135 THREAD_PRIORITY_TOP_APP_BOOST); 136 shellSplashscreenThread.start(); 137 return new HandlerExecutor(shellSplashscreenThread.getThreadHandler()); 138 } 139 140 /** 141 * Provide a Shell main-thread AnimationHandler. The AnimationHandler can be set on 142 * {@link android.animation.ValueAnimator}s and will ensure that the animation will run on 143 * the Shell main-thread with the SF vsync. 144 */ 145 @WMSingleton 146 @Provides 147 @ChoreographerSfVsync provideShellMainExecutorSfVsyncAnimationHandler( @hellMainThread ShellExecutor mainExecutor)148 public static AnimationHandler provideShellMainExecutorSfVsyncAnimationHandler( 149 @ShellMainThread ShellExecutor mainExecutor) { 150 try { 151 AnimationHandler handler = new AnimationHandler(); 152 mainExecutor.executeBlocking(() -> { 153 // This is called on the animation thread since it calls 154 // Choreographer.getSfInstance() which returns a thread-local Choreographer instance 155 // that uses the SF vsync 156 handler.setProvider(new SfVsyncFrameCallbackProvider()); 157 }); 158 return handler; 159 } catch (InterruptedException e) { 160 throw new RuntimeException("Failed to initialize SfVsync animation handler in 1s", e); 161 } 162 } 163 } 164