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