1 /* 2 * Copyright (C) 2021 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.wm.shell.dagger; 18 19 import static android.os.Process.THREAD_PRIORITY_BACKGROUND; 20 import static android.os.Process.THREAD_PRIORITY_DISPLAY; 21 import static android.os.Process.THREAD_PRIORITY_FOREGROUND; 22 import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST; 23 24 import android.content.Context; 25 import android.os.Build; 26 import android.os.Handler; 27 import android.os.HandlerThread; 28 import android.os.Looper; 29 import android.os.Trace; 30 import android.view.Choreographer; 31 32 import androidx.annotation.Nullable; 33 34 import com.android.wm.shell.R; 35 import com.android.wm.shell.common.HandlerExecutor; 36 import com.android.wm.shell.common.ShellExecutor; 37 import com.android.wm.shell.shared.annotations.ExternalMainThread; 38 import com.android.wm.shell.shared.annotations.ShellAnimationThread; 39 import com.android.wm.shell.shared.annotations.ShellBackgroundThread; 40 import com.android.wm.shell.shared.annotations.ShellDesktopThread; 41 import com.android.wm.shell.shared.annotations.ShellMainThread; 42 import com.android.wm.shell.shared.annotations.ShellSplashscreenThread; 43 44 import dagger.Module; 45 import dagger.Provides; 46 47 /** 48 * Provides basic concurrency-related dependencies from {@link com.android.wm.shell}, these 49 * dependencies are only accessible from components within the WM subcomponent. 50 */ 51 @Module 52 public abstract class WMShellConcurrencyModule { 53 54 private static final int MSGQ_SLOW_DELIVERY_THRESHOLD_MS = 30; 55 private static final int MSGQ_SLOW_DISPATCH_THRESHOLD_MS = 30; 56 57 /** 58 * Returns whether to enable a separate shell thread for the shell features. 59 */ enableShellMainThread(Context context)60 public static boolean enableShellMainThread(Context context) { 61 return context.getResources().getBoolean(R.bool.config_enableShellMainThread); 62 } 63 64 // 65 // Shell Concurrency - Components used for managing threading in the Shell and SysUI 66 // 67 68 69 /** 70 * Provide a SysUI main-thread Handler. 71 * 72 * Prefer the Main Executor when possible. 73 */ 74 @Provides 75 @ExternalMainThread provideMainHandler()76 public static Handler provideMainHandler() { 77 return new Handler(Looper.getMainLooper()); 78 } 79 80 /** 81 * Provide a SysUI main-thread Executor. 82 */ 83 @WMSingleton 84 @Provides 85 @ExternalMainThread provideSysUIMainExecutor( @xternalMainThread Handler sysuiMainHandler)86 public static ShellExecutor provideSysUIMainExecutor( 87 @ExternalMainThread Handler sysuiMainHandler) { 88 return new HandlerExecutor(sysuiMainHandler); 89 } 90 91 /** 92 * Creates a shell main thread to be injected into the shell components. This does not provide 93 * the {@param HandleThread}, but is used to create the thread prior to initializing the 94 * WM component, and is explicitly bound. 95 * 96 * See {@link com.android.systemui.SystemUIFactory#init(Context, boolean)}. 97 */ createShellMainThread()98 public static HandlerThread createShellMainThread() { 99 HandlerThread mainThread = new HandlerThread("wmshell.main", THREAD_PRIORITY_DISPLAY); 100 return mainThread; 101 } 102 103 /** 104 * Shell main-thread Handler, don't use this unless really necessary (ie. need to dedupe 105 * multiple types of messages, etc.) 106 * 107 * @param mainThread If non-null, this thread is expected to be started already 108 */ 109 @WMSingleton 110 @Provides 111 @ShellMainThread provideShellMainHandler(Context context, @Nullable @ShellMainThread HandlerThread mainThread, @ExternalMainThread Handler sysuiMainHandler)112 public static Handler provideShellMainHandler(Context context, 113 @Nullable @ShellMainThread HandlerThread mainThread, 114 @ExternalMainThread Handler sysuiMainHandler) { 115 if (enableShellMainThread(context)) { 116 if (mainThread == null) { 117 // If this thread wasn't pre-emptively started, then create and start it 118 mainThread = createShellMainThread(); 119 mainThread.start(); 120 } 121 if (Build.IS_DEBUGGABLE) { 122 mainThread.getLooper().setTraceTag(Trace.TRACE_TAG_WINDOW_MANAGER); 123 mainThread.getLooper().setSlowLogThresholdMs(MSGQ_SLOW_DISPATCH_THRESHOLD_MS, 124 MSGQ_SLOW_DELIVERY_THRESHOLD_MS); 125 } 126 return Handler.createAsync(mainThread.getLooper()); 127 } 128 return sysuiMainHandler; 129 } 130 131 /** 132 * Provide a Shell main-thread Executor. 133 */ 134 @WMSingleton 135 @Provides 136 @ShellMainThread provideShellMainExecutor(Context context, @ShellMainThread Handler mainHandler, @ExternalMainThread ShellExecutor sysuiMainExecutor)137 public static ShellExecutor provideShellMainExecutor(Context context, 138 @ShellMainThread Handler mainHandler, 139 @ExternalMainThread ShellExecutor sysuiMainExecutor) { 140 if (enableShellMainThread(context)) { 141 return new HandlerExecutor(mainHandler); 142 } 143 return sysuiMainExecutor; 144 } 145 146 /** 147 * Provide a Shell main-thread {@link Choreographer} with the app vsync. 148 * 149 * @param executor the executor of the shell main thread 150 */ 151 @WMSingleton 152 @Provides 153 @ShellMainThread provideShellMainChoreographer( @hellMainThread ShellExecutor executor)154 public static Choreographer provideShellMainChoreographer( 155 @ShellMainThread ShellExecutor executor) { 156 try { 157 final Choreographer[] choreographer = new Choreographer[1]; 158 executor.executeBlocking(() -> choreographer[0] = Choreographer.getInstance()); 159 return choreographer[0]; 160 } catch (InterruptedException e) { 161 throw new RuntimeException("Failed to obtain main Choreographer.", e); 162 } 163 } 164 165 /** Provide a Shell animation-thread Handler. */ 166 @WMSingleton 167 @Provides 168 @ShellAnimationThread provideShellAnimationHandler()169 public static Handler provideShellAnimationHandler() { 170 HandlerThread animThread = new HandlerThread("wmshell.anim", THREAD_PRIORITY_DISPLAY); 171 animThread.start(); 172 if (Build.IS_DEBUGGABLE) { 173 animThread.getLooper().setTraceTag(Trace.TRACE_TAG_WINDOW_MANAGER); 174 animThread.getLooper().setSlowLogThresholdMs(MSGQ_SLOW_DISPATCH_THRESHOLD_MS, 175 MSGQ_SLOW_DELIVERY_THRESHOLD_MS); 176 } 177 return Handler.createAsync(animThread.getLooper()); 178 } 179 180 /** 181 * Provide a Shell animation-thread Executor. 182 */ 183 @WMSingleton 184 @Provides 185 @ShellAnimationThread provideShellAnimationExecutor( @hellAnimationThread Handler animHandler )186 public static ShellExecutor provideShellAnimationExecutor( 187 @ShellAnimationThread Handler animHandler 188 ) { 189 return new HandlerExecutor(animHandler); 190 } 191 192 /** 193 * Provides a Shell splashscreen-thread Executor 194 */ 195 @WMSingleton 196 @Provides 197 @ShellSplashscreenThread provideSplashScreenExecutor()198 public static ShellExecutor provideSplashScreenExecutor() { 199 HandlerThread shellSplashscreenThread = new HandlerThread("wmshell.splashscreen", 200 THREAD_PRIORITY_TOP_APP_BOOST); 201 shellSplashscreenThread.start(); 202 return new HandlerExecutor(shellSplashscreenThread.getThreadHandler()); 203 } 204 205 /** 206 * Provides a Shell desktop thread Executor 207 */ 208 @WMSingleton 209 @Provides 210 @ShellDesktopThread provideDesktopModeMiscExecutor()211 public static ShellExecutor provideDesktopModeMiscExecutor() { 212 HandlerThread shellDesktopThread = new HandlerThread("wmshell.desktop", 213 THREAD_PRIORITY_TOP_APP_BOOST); 214 shellDesktopThread.start(); 215 return new HandlerExecutor(shellDesktopThread.getThreadHandler()); 216 } 217 218 /** 219 * Provides a Shell background thread Handler for low priority background tasks. 220 */ 221 @WMSingleton 222 @Provides 223 @ShellBackgroundThread provideSharedBackgroundHandler()224 public static Handler provideSharedBackgroundHandler() { 225 final HandlerThread shellBackgroundThread = new HandlerThread("wmshell.background", 226 THREAD_PRIORITY_BACKGROUND); 227 shellBackgroundThread.start(); 228 return shellBackgroundThread.getThreadHandler(); 229 } 230 231 /** 232 * Provides a Shell background thread Executor for low priority background tasks. The thread 233 * may also be boosted to THREAD_PRIORITY_FOREGROUND if necessary. 234 */ 235 @WMSingleton 236 @Provides 237 @ShellBackgroundThread provideSharedBackgroundExecutor( @hellBackgroundThread Handler handler)238 public static ShellExecutor provideSharedBackgroundExecutor( 239 @ShellBackgroundThread Handler handler) { 240 return new HandlerExecutor(handler, THREAD_PRIORITY_BACKGROUND, THREAD_PRIORITY_FOREGROUND); 241 } 242 } 243