1# Threading 2 3--- 4 5## Boundaries 6 7```text 8 Thread boundary 9 | 10 WM Shell | SystemUI 11 | 12 | 13FeatureController <-> FeatureInterface <--|--> WMShell <-> SysUI 14 | (^post to shell thread) | (^post to main thread) 15 ... | 16 | | 17 OtherControllers | 18``` 19 20## Threads 21 22We currently have multiple threads in use in the Shell library depending on the configuration by 23the product. 24- SysUI main thread (standard main thread) 25- `ShellMainThread` (only used if the resource `config_enableShellMainThread` is set true 26 (ie. phones)) 27 - This falls back to the SysUI main thread otherwise 28 - **Note**: 29 - This thread runs with `THREAD_PRIORITY_DISPLAY` priority since so many windowing-critical 30 components depend on it 31 - This is also the UI thread for almost all UI created by the Shell 32 - The Shell main thread Handler (and the Executor that wraps it) is async, so 33 messages/runnables used via this Handler are handled immediately if there is no sync 34 messages prior to it in the queue. 35- `ShellBackgroundThread` (for longer running tasks where we don't want to block the shell main 36 thread) 37 - This is always another thread even if config_enableShellMainThread is not set true 38 - **Note**: 39 - This thread runs with `THREAD_PRIORITY_BACKGROUND` priority 40- `ShellAnimationThread` (currently only used for Transitions and Splitscreen, but potentially all 41 animations could be offloaded here) 42- `ShellSplashScreenThread` (only for use with splashscreens) 43 44## Dagger setup 45 46The threading-related components are provided by the [WMShellConcurrencyModule](frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellConcurrencyModule.java), 47for example, the Executors and Handlers for the various threads that are used. You can request 48an executor of the necessary type by using the appropriate annotation for each of the threads (ie. 49`@ShellMainThread Executor`) when injecting into your Shell component. 50 51To get the SysUI main thread, you can use the `@Main` annotation. 52 53## Best practices 54 55### Components 56- Don't do initialization in the Shell component constructors 57 - If the host SysUI is not careful, it may construct the WMComponent dependencies on the main 58 thread, and this reduces the likelihood that components will intiailize on the wrong thread 59 in such cases 60- Be careful of using CountDownLatch and other blocking synchronization mechanisms in Shell code 61 - If the Shell main thread is not a separate thread, this will cause a deadlock 62- Callbacks, Observers, Listeners to any non-shell component should post onto main Shell thread 63 - This includes Binder calls, SysUI calls, BroadcastReceivers, etc. Basically any API that 64 takes a runnable should either be registered with the right Executor/Handler or posted to 65 the main Shell thread manually 66- Since everything in the Shell runs on the main Shell thread, you do **not** need to explicitly 67 `synchronize` your code (unless you are trying to prevent reentrantcy, but that can also be 68 done in other ways) 69 70### Handlers/Executors 71- You generally **never** need to create Handlers explicitly, instead inject `@ShellMainThread 72 ShellExecutor` instead 73 - This is a common pattern to defer logic in UI code, but the Handler created wraps the Looper 74 that is currently running, which can be wrong (see above for initialization vs construction) 75- That said, sometimes Handlers are necessary because Framework API only takes Handlers or you 76 want to dedupe multiple messages 77 - In such cases inject `@ShellMainThread Handler` or use view.getHandler() which should be OK 78 assuming that the view root was initialized on the main Shell thread 79- **Never use Looper.getMainLooper()** 80 - It's likely going to be wrong, you can inject `@Main ShellExecutor` to get the SysUI main thread 81 82### Testing 83- You can use a `TestShellExecutor` to control the processing of messages