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