Merge "Add sanitizers to libinput" into udc-qpr-dev
diff --git a/include/input/Input.h b/include/input/Input.h
index 1e810b4..fe0c775 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -30,7 +30,6 @@
#include <stdint.h>
#include <ui/Transform.h>
#include <utils/BitSet.h>
-#include <utils/RefBase.h>
#include <utils/Timers.h>
#include <array>
#include <limits>
diff --git a/libs/ultrahdr/jpegr.cpp b/libs/ultrahdr/jpegr.cpp
index ef927e3..cb8197c 100644
--- a/libs/ultrahdr/jpegr.cpp
+++ b/libs/ultrahdr/jpegr.cpp
@@ -1041,21 +1041,18 @@
return ERROR_JPEGR_INVALID_NULL_PTR;
}
- size_t src_luma_stride = src->luma_stride;
- size_t src_chroma_stride = src->chroma_stride;
uint16_t* src_luma_data = reinterpret_cast<uint16_t*>(src->data);
- uint16_t* src_chroma_data = reinterpret_cast<uint16_t*>(src->chroma_data);
+ size_t src_luma_stride = src->luma_stride == 0 ? src->width : src->luma_stride;
- if (src_chroma_data == nullptr) {
- src_chroma_data = &reinterpret_cast<uint16_t*>(src->data)[src_luma_stride * src->height];
+ uint16_t* src_chroma_data;
+ size_t src_chroma_stride;
+ if (src->chroma_data == nullptr) {
+ src_chroma_stride = src_luma_stride;
+ src_chroma_data = &reinterpret_cast<uint16_t*>(src->data)[src_luma_stride * src->height];
+ } else {
+ src_chroma_stride = src->chroma_stride;
+ src_chroma_data = reinterpret_cast<uint16_t*>(src->chroma_data);
}
- if (src_luma_stride == 0) {
- src_luma_stride = src->width;
- }
- if (src_chroma_stride == 0) {
- src_chroma_stride = src_luma_stride;
- }
-
dest->width = src->width;
dest->height = src->height;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index a3c129e..9125fe4 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -2811,6 +2811,30 @@
}
}
+std::optional<InputTarget> InputDispatcher::createInputTargetLocked(
+ const sp<android::gui::WindowInfoHandle>& windowHandle,
+ ftl::Flags<InputTarget::Flags> targetFlags,
+ std::optional<nsecs_t> firstDownTimeInTarget) const {
+ std::shared_ptr<InputChannel> inputChannel = getInputChannelLocked(windowHandle->getToken());
+ if (inputChannel == nullptr) {
+ ALOGW("Not creating InputTarget for %s, no input channel", windowHandle->getName().c_str());
+ return {};
+ }
+ InputTarget inputTarget;
+ inputTarget.inputChannel = inputChannel;
+ inputTarget.flags = targetFlags;
+ inputTarget.globalScaleFactor = windowHandle->getInfo()->globalScaleFactor;
+ inputTarget.firstDownTimeInTarget = firstDownTimeInTarget;
+ const auto& displayInfoIt = mDisplayInfos.find(windowHandle->getInfo()->displayId);
+ if (displayInfoIt != mDisplayInfos.end()) {
+ inputTarget.displayTransform = displayInfoIt->second.transform;
+ } else {
+ // DisplayInfo not found for this window on display windowInfo->displayId.
+ // TODO(b/198444055): Make this an error message after 'setInputWindows' API is removed.
+ }
+ return inputTarget;
+}
+
void InputDispatcher::addWindowTargetLocked(const sp<WindowInfoHandle>& windowHandle,
ftl::Flags<InputTarget::Flags> targetFlags,
std::bitset<MAX_POINTER_ID + 1> pointerIds,
@@ -2826,25 +2850,12 @@
const WindowInfo* windowInfo = windowHandle->getInfo();
if (it == inputTargets.end()) {
- InputTarget inputTarget;
- std::shared_ptr<InputChannel> inputChannel =
- getInputChannelLocked(windowHandle->getToken());
- if (inputChannel == nullptr) {
- ALOGW("Window %s already unregistered input channel", windowHandle->getName().c_str());
+ std::optional<InputTarget> target =
+ createInputTargetLocked(windowHandle, targetFlags, firstDownTimeInTarget);
+ if (!target) {
return;
}
- inputTarget.inputChannel = inputChannel;
- inputTarget.flags = targetFlags;
- inputTarget.globalScaleFactor = windowInfo->globalScaleFactor;
- inputTarget.firstDownTimeInTarget = firstDownTimeInTarget;
- const auto& displayInfoIt = mDisplayInfos.find(windowInfo->displayId);
- if (displayInfoIt != mDisplayInfos.end()) {
- inputTarget.displayTransform = displayInfoIt->second.transform;
- } else {
- // DisplayInfo not found for this window on display windowInfo->displayId.
- // TODO(b/198444055): Make this an error message after 'setInputWindows' API is removed.
- }
- inputTargets.push_back(inputTarget);
+ inputTargets.push_back(*target);
it = inputTargets.end() - 1;
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 9b12f2f..0e9cfef 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -556,6 +556,10 @@
std::vector<Monitor> selectResponsiveMonitorsLocked(
const std::vector<Monitor>& gestureMonitors) const REQUIRES(mLock);
+ std::optional<InputTarget> createInputTargetLocked(
+ const sp<android::gui::WindowInfoHandle>& windowHandle,
+ ftl::Flags<InputTarget::Flags> targetFlags,
+ std::optional<nsecs_t> firstDownTimeInTarget) const REQUIRES(mLock);
void addWindowTargetLocked(const sp<android::gui::WindowInfoHandle>& windowHandle,
ftl::Flags<InputTarget::Flags> targetFlags,
std::bitset<MAX_POINTER_ID + 1> pointerIds,
diff --git a/services/surfaceflinger/FrontEnd/readme.md b/services/surfaceflinger/FrontEnd/readme.md
new file mode 100644
index 0000000..e5f51a5
--- /dev/null
+++ b/services/surfaceflinger/FrontEnd/readme.md
@@ -0,0 +1,110 @@
+# SurfaceFlinger FrontEnd
+
+SurfaceFlinger FrontEnd implements the client APIs that describe how buffers should be
+composited on the screen. Layers are used to capture how the buffer should be composited
+and each buffer is associated with a Layer. Transactions contain an atomic set of changes
+to one or more of these layers. The FrontEnd consumes these transactions, maintains the
+layer lifecycle, and provides a snapshot to the composition engine every frame that
+describes how a set of buffers should be composited.
+
+
+
+## Layers
+Layers are used to describe how a buffer should be placed on the display relative to other
+buffers. They are represented as a hierarchy, similar to a scene graph. Child layers can
+inherit some properties from their parents, which allows higher-level system components to
+maintain policies at different levels without needing to understand the entire hierarchy.
+This allows control to be delegated to different parts of the system - such as SystemServer,
+SysUI and Apps.
+
+### Layer Lifecycle
+Layer is created by a client. The client receives a strong binder reference to the layer
+handle, which will keep the layer alive as long as the client holds the reference. The
+layer can also be kept alive if the layer has a parent, since the parent will hold a
+strong reference to the children. If the layer is not reachable but its handle is alive,
+the layer will be offscreen and its resources will not be freed. Clients must explicitly
+release all references to the handle as soon as it's done with the layer. It's strongly
+recommended to explicitly release the layer in Java and not rely on the GC.
+
+
+
+## Transactions
+Transactions contain a group of changes to one or more layers that are applied together.
+Transactions can be merged to apply a set of changes atomically. Merges are associative,
+meaning how you group the merges does not matter, but they are not commutative, meaning
+that the order in which you merge them does.
+For example:
+
+`Transaction a; a.setAlpha(sc, 2);`
+
+`Transaction b; b.setAlpha(sc, 4);`
+
+`a.merge(b)` is not the same as `b.merge(a)`
+
+<p>
+
+`Transaction c; c.setAlpha(sc, 6);`
+
+`a.merge(b).merge(c)` is the same as `b.merge(c); a.merge(b);`
+
+Transactions are queued in SurfaceFlinger per ApplyToken so order is only guaranteed for
+Transactions with the same applyToken. By default each process and each buffer producer
+provides a unique ApplyToken. This prevents clients from affecting one another, and possibly
+slowing each other down.
+
+
+
+## Architecture
+SurfaceFlinger FrontEnd intends to optimize for predictability and performance because state
+generation is on the hotpath. Simple buffer updates should be as fast as possible, and they
+should be consistently fast. This means avoiding contention (e.g., locks) and context
+switching. We also want to avoid doing anything that does not contribute to putting a pixel
+on the display.
+
+The pipeline can be broken down into five stages:
+- Queue and filter transactions that are ready to be committed.
+- Handle layer lifecycles and update server-side state per layer.
+- Generate and/or update the traversal trees.
+- Generate a z-ordered list of snapshots.
+- Emit callbacks back to clients
+
+
+### TransactionHandler
+TransactionHandler is responsible for queuing and filtering transactions that are ready to
+be applied. On commit, we filter the transactions that are ready. We provide an interface
+for other components to apply their own filter to determine if a transaction is ready to be
+applied.
+
+
+### LayerLifecycleManager
+RequestedLayerState is a simple data class that stores the server side layer state.
+Transactions are merged into this state, similar to how transactions can be merged on the
+client side. The states can always be reconstructed from LayerCreationArgs and a list of
+transactions. LayerLifecycleManager keeps track of Layer handle lifecycle and the layer
+lifecycle itself. It consumes a list of transactions and generates a list of server side
+states and change flags. Other components can register to listen to layer lifecycles.
+
+
+### LayerHierarchyBuilder
+LayerHierarchyBuilder consumes a list of RequestedLayerStates to generate a LayerHierarchy.
+The hierarchy provides functions for breadth-first traversal and z-order traversal of the
+entire tree or a subtree. Internally, the hierarchy is represented by a graph. Mirrored
+layers are represented by the same node in the graph with multiple parents. This allows us
+to implement mirroring without cloning Layers and maintaining complex hierarchies.
+
+
+### LayerSnapshotBuilder
+LayerSnapshotBuilder consumes a LayerHierarchy along with a list of RequestedLayerStates to
+generate a flattened z-ordered list of LayerSnapshots. LayerSnapshots contain all the data
+required for CompositionEngine and RenderEngine. It has no dependencies to FrontEnd, or the
+LayerHierarchy used to create them. They can be cloned and consumed freely. Other consumers
+like WindowInfo listeners (input and accessibility) also updated from these snapshots.
+
+Change flags are used to efficiently traverse this hierarchy where possible. This allows us
+to support short circuiting parts of the hierarchy, partial hierarchy updates and fast paths
+for buffer updates.
+
+
+While they can be cloned, the current implementation moves the snapshot from FrontEnd to
+CompositionEngine to avoid needless work in the hotpath. For snapshot consumers not critical
+to composition, the goal is to clone the snapshots and consume them on a background thread.
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 736b752..93fcca3 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -6984,7 +6984,8 @@
const auto dataspaceForColorMode = ui::pickDataspaceFor(state.colorMode);
- if (capturingHdrLayers && !hintForSeamlessTransition) {
+ // TODO: Enable once HDR screenshots are ready.
+ if constexpr (/* DISABLES CODE */ (false)) {
// For now since we only support 8-bit screenshots, just use HLG and
// assume that 1.0 >= display max luminance. This isn't quite as future
// proof as PQ is, but is good enough.