Merge "Adding some Shell documentation" into tm-qpr-dev am: 5ff3c0e94c
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/19230676 Change-Id: I06610ee9728720bd2fe7e230bf9b1734c2960b15 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -1,13 +0,0 @@
|
||||
The dagger modules in this directory can be included by the host SysUI using the Shell library for
|
||||
explicity injection of Shell components. Apps using this library are not required to use these
|
||||
dagger modules for setup, but it is recommended for them to include them as needed.
|
||||
|
||||
The modules are currently inherited as such:
|
||||
|
||||
+- WMShellBaseModule (common shell features across SysUI)
|
||||
|
|
||||
+- WMShellModule (handheld)
|
||||
|
|
||||
+- TvPipModule (tv pip)
|
||||
|
|
||||
+- TvWMShellModule (tv)
|
||||
@@ -0,0 +1,18 @@
|
||||
# Window Manager Shell Readme
|
||||
|
||||
The following docs present more detail about the implementation of the WMShell library (in no
|
||||
particular order):
|
||||
|
||||
1) [What is the Shell](overview.md)
|
||||
2) [Integration with SystemUI & Launcher](sysui.md)
|
||||
3) [Usage of Dagger](dagger.md)
|
||||
4) [Threading model in the Shell](threading.md)
|
||||
5) [Making changes in the Shell](changes.md)
|
||||
6) [Extending the Shell for Products/OEMs](extending.md)
|
||||
7) [Debugging in the Shell](debugging.md)
|
||||
8) [Testing in the Shell](testing.md)
|
||||
|
||||
Todo
|
||||
- Per-feature docs
|
||||
- Feature flagging
|
||||
- Best practices
|
||||
@@ -0,0 +1,73 @@
|
||||
# Making changes in the Shell
|
||||
|
||||
---
|
||||
|
||||
## Code reviews
|
||||
|
||||
In addition to the individual reviewers who are most familiar with the changes you are making,
|
||||
please also add [wm-code-reviewers@google.com](http://g/wm-code-reviewers) to keep other WM folks
|
||||
in the loop.
|
||||
|
||||
## Adding new code
|
||||
|
||||
### Internal Shell utility classes
|
||||
If the new component is used only within the WMShell library, then there are no special
|
||||
considerations, go ahead and add it (in the `com.android.wm.shell.common` package for example)
|
||||
and make sure the appropriate [unit tests](testing.md) are added.
|
||||
|
||||
### Internal Shell components
|
||||
If the new component is to be used by other components/features within the Shell library, then
|
||||
you can create an appropriate package for this component to add your new code. The current
|
||||
pattern is to have a single `<Component name>Controller` that handles the initialization of the
|
||||
component.
|
||||
|
||||
As mentioned in the [Dagger usage](dagger.md) docs, you need to determine whether it should go into:
|
||||
- `WMShellBaseModule` for components that other base & product components will depend on
|
||||
- or `WMShellModule`, `TvWmShellModule`, etc. for product specific components that no base
|
||||
components depend on
|
||||
|
||||
### SysUI accessible components
|
||||
In addition to doing the above, you will also need to provide an interface for calling to SysUI
|
||||
from the Shell and vice versa. The current pattern is to have a parallel `Optional<Component name>`
|
||||
interface that the `<Component name>Controller` implements and handles on the main Shell thread.
|
||||
|
||||
In addition, because components accessible to SysUI injection are explicitly listed, you'll have to
|
||||
add an appropriate method in `WMComponent` to get the interface and update the `Builder` in
|
||||
`SysUIComponent` to take the interface so it can be injected in SysUI code. The binding between
|
||||
the two is done in `SystemUIFactory#init()` which will need to be updated as well.
|
||||
|
||||
### Launcher accessible components
|
||||
Because Launcher is not a part of SystemUI and is a separate process, exposing controllers to
|
||||
Launcher requires a new AIDL interface to be created and implemented by the controller. The
|
||||
implementation of the stub interface in the controller otherwise behaves similar to the interface
|
||||
to SysUI where it posts the work to the main Shell thread.
|
||||
|
||||
### Component initialization
|
||||
To initialize the component:
|
||||
- On the Shell side, update `ShellInitImpl` to get a signal to initialize when the SysUI is started
|
||||
- On the SysUI side, update `WMShell` to setup any bindings for the component that depend on
|
||||
SysUI code
|
||||
|
||||
### General Do's & Dont's
|
||||
Do:
|
||||
- Do add unit tests for all new components
|
||||
- Do keep controllers simple and break them down as needed
|
||||
|
||||
Don't:
|
||||
- **Don't** do initialization in the constructor, only do initialization in the init callbacks.
|
||||
Otherwise it complicates the building of the dependency graph.
|
||||
- **Don't** create dependencies from base-module components on specific features (the base module
|
||||
is intended for use with all products)
|
||||
- Try adding a mechanism to register and listen for changes from the base module component instead
|
||||
- **Don't** add blocking synchronous calls in the SysUI interface between Shell & SysUI
|
||||
- Try adding a push-mechanism to share data, or an async callback to request data
|
||||
|
||||
### Exposing shared code for use in Launcher
|
||||
Launcher doesn't currently build against the Shell library, but needs to have access to some shared
|
||||
AIDL interfaces and constants. Currently, all AIDL files, and classes under the
|
||||
`com.android.wm.shell.util` package are automatically built into the `SystemUISharedLib` that
|
||||
Launcher uses.
|
||||
|
||||
If the new code doesn't fall into those categories, they can be added explicitly in the Shell's
|
||||
[Android.bp](frameworks/base/libs/WindowManager/Shell/Android.bp) file under the
|
||||
`wm_shell_util-sources` filegroup.
|
||||
@@ -0,0 +1,50 @@
|
||||
# Usage of Dagger in the Shell library
|
||||
|
||||
---
|
||||
|
||||
## Dependencies
|
||||
|
||||
Dagger is not required to use the Shell library, but it has a lot of obvious benefits:
|
||||
|
||||
- Not having to worry about how to instantiate all the dependencies of a class, especially as
|
||||
dependencies evolve (ie. product controller depends on base controller)
|
||||
- Can create boundaries within the same app to encourage better code modularity
|
||||
|
||||
As such, the Shell also tries to provide some reasonable out-of-the-box modules for use with Dagger.
|
||||
|
||||
## Modules
|
||||
|
||||
All the Dagger related code in the Shell can be found in the `com.android.wm.shell.dagger` package,
|
||||
this is intentional as it keeps the "magic" in a single location. The explicit nature of how
|
||||
components in the shell are provided is as a result a bit more verbose, but it makes it easy for
|
||||
developers to jump into a few select files and understand how different components are provided
|
||||
(especially as products override components).
|
||||
|
||||
The module dependency tree looks a bit like:
|
||||
- [WMShellConcurrencyModule](frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellConcurrencyModule.java)
|
||||
(provides threading-related components)
|
||||
- [WMShellBaseModule](frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java)
|
||||
(provides components that are likely common to all products, ie. DisplayController,
|
||||
Transactions, etc.)
|
||||
- [WMShellModule](frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java)
|
||||
(phone/tablet specific components only)
|
||||
- [TvPipModule](frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java)
|
||||
(PIP specific components for TV)
|
||||
- [TvWMShellModule](frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java)
|
||||
(TV specific components only)
|
||||
- etc.
|
||||
|
||||
Ideally features could be abstracted out into their own modules and included as needed by each
|
||||
product.
|
||||
|
||||
## Overriding base components
|
||||
|
||||
In some rare cases, there are base components that can change behavior depending on which
|
||||
product it runs on. If there are hooks that can be added to the component, that is the
|
||||
preferable approach.
|
||||
|
||||
The alternative is to use the [@DynamicOverride](frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/DynamicOverride.java)
|
||||
annotation to allow the product module to provide an implementation that the base module can
|
||||
reference. This is most useful if the existence of the entire component is controlled by the
|
||||
product and the override implementation is optional (there is a default implementation). More
|
||||
details can be found in the class's javadoc.
|
||||
@@ -0,0 +1,69 @@
|
||||
# Debugging in the Shell
|
||||
|
||||
---
|
||||
|
||||
## Logging & ProtoLogs
|
||||
|
||||
The interactions in the Shell can be pretty complicated, so having good logging is crucial to
|
||||
debugging problems that arise (especially in dogfood). The Shell uses the same efficient Protolog
|
||||
mechanism as WM Core, which can be enabled at runtime on debug devices.
|
||||
|
||||
**TLDR** Don’t use Logs or Slogs except for error cases, Protologs are much more flexible,
|
||||
easy to add and easy to use
|
||||
|
||||
### Adding a new ProtoLog
|
||||
Update `ShellProtoLogGroup` to include a new log group (ie. NEW_FEATURE) for the content you want to
|
||||
log. ProtoLog log calls mirror Log.v/d/e(), and take a format message and arguments:
|
||||
```java
|
||||
ProtoLog.v(NEW_FEATURE, "Test log w/ params: %d %s", 1, “a”)
|
||||
```
|
||||
This code itself will not compile by itself, but the `protologtool` will preprocess the file when
|
||||
building to check the log state (is enabled) before printing the print format style log.
|
||||
|
||||
**Notes**
|
||||
- ProtoLogs currently only work from soong builds (ie. via make/mp). We need to reimplement the
|
||||
tool for use with SysUI-studio
|
||||
- Non-text ProtoLogs are not currently supported with the Shell library (you can't view them with
|
||||
traces in Winscope)
|
||||
|
||||
### Enabling ProtoLog command line logging
|
||||
Run these commands to enable protologs for both WM Core and WM Shell to print to logcat.
|
||||
```shell
|
||||
adb shell wm logging enable-text NEW_FEATURE
|
||||
adb shell wm logging disable-text NEW_FEATURE
|
||||
```
|
||||
|
||||
## Winscope Tracing
|
||||
|
||||
The Winscope tool is extremely useful in determining what is happening on-screen in both
|
||||
WindowManager and SurfaceFlinger. Follow [go/winscope](http://go/winscope-help) to learn how to
|
||||
use the tool.
|
||||
|
||||
In addition, there is limited preliminary support for Winscope tracing componetns in the Shell,
|
||||
which involves adding trace fields to [wm_shell_trace.proto](frameworks/base/libs/WindowManager/Shell/proto/wm_shell_trace.proto)
|
||||
file and ensure it is updated as a part of `WMShell#writeToProto`.
|
||||
|
||||
Tracing can be started via the shell command (to be added to the Winscope tool as needed):
|
||||
```shell
|
||||
adb shell cmd statusbar tracing start
|
||||
adb shell cmd statusbar tracing stop
|
||||
```
|
||||
|
||||
## Dumps
|
||||
|
||||
Because the Shell library is built as a part of SystemUI, dumping the state is currently done as a
|
||||
part of dumping the SystemUI service. Dumping the Shell specific data can be done by specifying the
|
||||
WMShell SysUI service:
|
||||
|
||||
```shell
|
||||
adb shell dumpsys activity service SystemUIService WMShell
|
||||
```
|
||||
|
||||
If information should be added to the dump, make updates to:
|
||||
- `WMShell` if you are dumping SysUI state
|
||||
- `ShellCommandHandler` if you are dumping Shell state
|
||||
|
||||
## Debugging in Android Studio
|
||||
|
||||
If you are using the [go/sysui-studio](http://go/sysui-studio) project, then you can debug Shell
|
||||
code directly from Android Studio like any other app.
|
||||
@@ -0,0 +1,13 @@
|
||||
# Extending the Shell for Products/OEMs
|
||||
|
||||
---
|
||||
|
||||
## General Do's & Dont's
|
||||
|
||||
Do:
|
||||
-
|
||||
|
||||
Don't
|
||||
- **Don't** override classes provided by WMShellBaseModule, it makes it difficult to make
|
||||
simple changes to the Shell library base modules which are shared by all products
|
||||
- If possible add mechanisms to modify the base class behavior
|
||||
@@ -0,0 +1,58 @@
|
||||
# What is the WindowManager Shell
|
||||
|
||||
---
|
||||
|
||||
## Motivation
|
||||
|
||||
The primary motivation for the WindowManager Shell (WMShell) library is to effectively scale
|
||||
WindowManager by making it easy™ and safe to create windowing features to fit the needs of
|
||||
various Android products and form factors.
|
||||
|
||||
To achieve this, WindowManager separates the policy of managing windows (WMCore) from the
|
||||
presentation of surfaces (WMShell) and provides a minimal interface boundary for the two to
|
||||
communicate.
|
||||
|
||||
## Who is using the library?
|
||||
|
||||
Currently, the WMShell library is used to drive the windowing experience on handheld
|
||||
(phones & tablets), TV, Auto, Arc++, and Wear to varying degrees.
|
||||
|
||||
## Where does the code live
|
||||
|
||||
The core WMShell library code is currently located in the [frameworks/base/libs/WindowManager/Shell](frameworks/base/libs/WindowManager/Shell)
|
||||
directory and is included as a part dependency of the host SystemUI apk.
|
||||
|
||||
## How do I build the Shell library
|
||||
|
||||
The library can be built directly by running (using [go/makepush](http://go/makepush)):
|
||||
```shell
|
||||
mp :WindowManager-Shell
|
||||
```
|
||||
But this is mainly useful for inspecting the contents of the library or verifying it builds. The
|
||||
various targets can be found in the Shell library's [Android.bp](frameworks/base/libs/WindowManager/Shell/Android.bp)
|
||||
file.
|
||||
|
||||
Normally, you would build it as a part of the host SystemUI, for example via commandline:
|
||||
```shell
|
||||
# Phone SystemUI variant
|
||||
mp sysuig
|
||||
# Building Shell & SysUI changes along w/ framework changes
|
||||
mp core services sysuig
|
||||
```
|
||||
|
||||
Or preferably, if you are making WMShell/SysUI only changes (no other framework changes), then
|
||||
building via [go/sysui-studio](http://go/sysui-studio) allows for very quick iteration (one click
|
||||
build and push of SysUI in < 30s).
|
||||
|
||||
If you are making framework changes and are using `aidegen` to set up your platform IDE, make sure
|
||||
to include the appropriate directories to build, for example:
|
||||
```shell
|
||||
# frameworks/base will include base/libs/WindowManager/Shell and base/packages/SystemUI
|
||||
aidegen frameworks/base \
|
||||
vendor/<oem>/packages/SystemUI \
|
||||
...
|
||||
```
|
||||
|
||||
## Other useful links
|
||||
- [go/o-o-summit-20](go/o-o-summit-20) (Video presentations from the WM team)
|
||||
- [go/o-o-summit-21](go/o-o-summit-21)
|
||||
@@ -0,0 +1,55 @@
|
||||
# Shell & SystemUI
|
||||
|
||||
---
|
||||
|
||||
## Setup
|
||||
|
||||
The SystemUI of various products depend on and build against the WM Shell library. To ensure
|
||||
that we don't inadvertently build dependencies between the Shell library and one particular
|
||||
product (ie. handheld SysUI), we deliberately separate the initialization of the WM Shell
|
||||
component from the SysUI component when set up through Dagger.
|
||||
|
||||
**TLDR** Initialize everything as needed in the WM component scope and export only well
|
||||
defined interfaces to SysUI.
|
||||
|
||||
## Initialization
|
||||
|
||||
There are more details in the Dagger docs, but the general overview of the SysUI/Shell
|
||||
initialization flow is such:
|
||||
|
||||
1) SysUI Global scope is initialize (see `GlobalModule` and its included modules)
|
||||
2) WM Shell scope is initialized, for example
|
||||
1) On phones: `WMComponent` includes `WMShellModule` which includes `WMShellBaseModule`
|
||||
(common to all SysUI)
|
||||
2) On TVs: `TvWMComponent` includes `TvWMShellModule` which includes `WMShellBaseModule`
|
||||
3) etc.
|
||||
3) SysUI explicitly passes interfaces provided from the `WMComponent` to `SysUIComponent` via
|
||||
the `SysUIComponent#Builder`, then builds the SysUI scoped components
|
||||
4) `WMShell` is the SystemUI “service” (in the SysUI scope) that initializes with the app after the
|
||||
SystemUI part of the dependency graph has been created. It contains the binding code between the
|
||||
interfaces provided by the Shell and the rest of SystemUI.
|
||||
5) SysUI can inject the interfaces into its own components
|
||||
|
||||
More detail can be found in [go/wm-sysui-dagger](http://go/wm-sysui-dagger).
|
||||
|
||||
## Interfaces to Shell components
|
||||
|
||||
Within the same process, the WM Shell components can be running on a different thread than the main
|
||||
SysUI thread (disabled on certain products). This introduces challenges where we have to be
|
||||
careful about how SysUI calls into the Shell and vice versa.
|
||||
|
||||
As a result, we enforce explicit interfaces between SysUI and Shell components, and the
|
||||
implementations of the interfaces on each side need to post to the right thread before it calls
|
||||
into other code.
|
||||
|
||||
For example, you might have:
|
||||
1) (Shell) ShellFeature interface to be used from SysUI
|
||||
2) (Shell) ShellFeatureController handles logic, implements ShellFeature interface and posts to
|
||||
main Shell thread
|
||||
3) SysUI application init injects Optional<ShellFeature> as an interface to SysUI to call
|
||||
4) (SysUI) SysUIFeature depends on ShellFeature interface
|
||||
5) (SysUI) SysUIFeature injects Optional<ShellFeature>, and sets up a callback for the Shell to
|
||||
call, and the callback posts to the main SysUI thread
|
||||
|
||||
Adding an interface to a Shell component may seem like a lot of boiler plate, but is currently
|
||||
necessary to maintain proper threading and logic isolation.
|
||||
@@ -0,0 +1,49 @@
|
||||
# Testing
|
||||
|
||||
---
|
||||
|
||||
## Unit tests
|
||||
|
||||
New WM Shell unit tests can be added to the
|
||||
[Shell/tests/unittest](frameworks/base/libs/WindowManager/Shell/tests/unittest) directory, and can
|
||||
be run via command line using `atest`:
|
||||
```shell
|
||||
atest WMShellUnitTests
|
||||
```
|
||||
|
||||
If you use the SysUI Studio project, you can run and debug tests directly in the source files
|
||||
(click on the little arrows next to the test class or test method).
|
||||
|
||||
These unit tests are run as a part of WindowManager presubmit, and the dashboards for these unit
|
||||
tests tests can be found at [go/wm-tests](http://go/wm-tests).
|
||||
|
||||
This [GCL file](http://go/wm-unit-tests-gcl) configures the tests being run on the server.
|
||||
|
||||
## Flicker tests
|
||||
|
||||
Flicker tests are tests that perform actions and make assertions on the state in Window Manager
|
||||
and SurfaceFlinger traces captured during the run.
|
||||
|
||||
New WM Shell Flicker tests can be added to the
|
||||
[Shell/tests/flicker](frameworks/base/libs/WindowManager/Shell/tests/flicker) directory, and can
|
||||
be run via command line using `atest`:
|
||||
```shell
|
||||
atest WMShellFlickerTests
|
||||
```
|
||||
|
||||
**Note**: Currently Flicker tests can only be run from the commandline and not via SysUI Studio
|
||||
|
||||
A subset of the flicker tests tests are run as a part of WindowManager presubmit, and the
|
||||
dashboards for these tests tests can be found at [go/wm-tests-flicker](http://go/wm-tests-flicker).
|
||||
|
||||
## CTS tests
|
||||
|
||||
Some windowing features also have CTS tests to ensure consistent behavior across OEMs. For example:
|
||||
- Picture-in-Picture:
|
||||
[PinnedStackTests](cts/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java)
|
||||
- etc.
|
||||
|
||||
These can also be run via commandline only using `atest`, for example:
|
||||
```shell
|
||||
atest PinnedStackTests
|
||||
```
|
||||
@@ -0,0 +1,83 @@
|
||||
# Threading
|
||||
|
||||
---
|
||||
|
||||
## Boundaries
|
||||
|
||||
```text
|
||||
Thread boundary
|
||||
|
|
||||
WM Shell | SystemUI
|
||||
|
|
||||
|
|
||||
FeatureController <-> FeatureInterface <--|--> WMShell <-> SysUI
|
||||
| (^post to shell thread) | (^post to main thread)
|
||||
... |
|
||||
| |
|
||||
OtherControllers |
|
||||
```
|
||||
|
||||
## Threads
|
||||
|
||||
We currently have multiple threads in use in the Shell library depending on the configuration by
|
||||
the product.
|
||||
- SysUI main thread (standard main thread)
|
||||
- `ShellMainThread` (only used if the resource `config_enableShellMainThread` is set true
|
||||
(ie. phones))
|
||||
- This falls back to the SysUI main thread otherwise
|
||||
- **Note**:
|
||||
- This thread runs with `THREAD_PRIORITY_DISPLAY` priority since so many windowing-critical
|
||||
components depend on it
|
||||
- This is also the UI thread for almost all UI created by the Shell
|
||||
- The Shell main thread Handler (and the Executor that wraps it) is async, so
|
||||
messages/runnables used via this Handler are handled immediately if there is no sync
|
||||
messages prior to it in the queue.
|
||||
- `ShellBackgroundThread` (for longer running tasks where we don't want to block the shell main
|
||||
thread)
|
||||
- This is always another thread even if config_enableShellMainThread is not set true
|
||||
- **Note**:
|
||||
- This thread runs with `THREAD_PRIORITY_BACKGROUND` priority
|
||||
- `ShellAnimationThread` (currently only used for Transitions and Splitscreen, but potentially all
|
||||
animations could be offloaded here)
|
||||
- `ShellSplashScreenThread` (only for use with splashscreens)
|
||||
|
||||
## Dagger setup
|
||||
|
||||
The threading-related components are provided by the [WMShellConcurrencyModule](frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellConcurrencyModule.java),
|
||||
for example, the Executors and Handlers for the various threads that are used. You can request
|
||||
an executor of the necessary type by using the appropriate annotation for each of the threads (ie.
|
||||
`@ShellMainThread Executor`) when injecting into your Shell component.
|
||||
|
||||
To get the SysUI main thread, you can use the `@Main` annotation.
|
||||
|
||||
## Best practices
|
||||
|
||||
### Components
|
||||
- Don't do initialization in the Shell component constructors
|
||||
- If the host SysUI is not careful, it may construct the WMComponent dependencies on the main
|
||||
thread, and this reduces the likelihood that components will intiailize on the wrong thread
|
||||
in such cases
|
||||
- Be careful of using CountDownLatch and other blocking synchronization mechanisms in Shell code
|
||||
- If the Shell main thread is not a separate thread, this will cause a deadlock
|
||||
- Callbacks, Observers, Listeners to any non-shell component should post onto main Shell thread
|
||||
- This includes Binder calls, SysUI calls, BroadcastReceivers, etc. Basically any API that
|
||||
takes a runnable should either be registered with the right Executor/Handler or posted to
|
||||
the main Shell thread manually
|
||||
- Since everything in the Shell runs on the main Shell thread, you do **not** need to explicitly
|
||||
`synchronize` your code (unless you are trying to prevent reentrantcy, but that can also be
|
||||
done in other ways)
|
||||
|
||||
### Handlers/Executors
|
||||
- You generally **never** need to create Handlers explicitly, instead inject `@ShellMainThread
|
||||
ShellExecutor` instead
|
||||
- This is a common pattern to defer logic in UI code, but the Handler created wraps the Looper
|
||||
that is currently running, which can be wrong (see above for initialization vs construction)
|
||||
- That said, sometimes Handlers are necessary because Framework API only takes Handlers or you
|
||||
want to dedupe multiple messages
|
||||
- In such cases inject `@ShellMainThread Handler` or use view.getHandler() which should be OK
|
||||
assuming that the view root was initialized on the main Shell thread
|
||||
- **Never use Looper.getMainLooper()**
|
||||
- It's likely going to be wrong, you can inject `@Main ShellExecutor` to get the SysUI main thread
|
||||
|
||||
### Testing
|
||||
- You can use a `TestShellExecutor` to control the processing of messages
|
||||
Reference in New Issue
Block a user