Merge "SF: add render frame rate dimension to RefreshRateSelector"
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 07d0a65..4b07608 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -966,7 +966,15 @@
}
}
+void Parcel::setEnforceNoDataAvail(bool enforceNoDataAvail) {
+ mEnforceNoDataAvail = enforceNoDataAvail;
+}
+
binder::Status Parcel::enforceNoDataAvail() const {
+ if (!mEnforceNoDataAvail) {
+ return binder::Status::ok();
+ }
+
const auto n = dataAvail();
if (n == 0) {
return binder::Status::ok();
@@ -3077,6 +3085,7 @@
mAllowFds = true;
mDeallocZero = false;
mOwner = nullptr;
+ mEnforceNoDataAvail = true;
}
void Parcel::scanForFds() const {
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index bd72a53..0820cd1 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -531,53 +531,35 @@
LOG_RPC_DETAIL("Setting up socket server %s", addr.toString().c_str());
LOG_ALWAYS_FATAL_IF(hasServer(), "Each RpcServer can only have one server.");
- RpcTransportFd transportFd(unique_fd(TEMP_FAILURE_RETRY(
- socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0))));
- if (!transportFd.fd.ok()) {
+ unique_fd socket_fd(TEMP_FAILURE_RETRY(
+ socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)));
+ if (!socket_fd.ok()) {
int savedErrno = errno;
ALOGE("Could not create socket: %s", strerror(savedErrno));
return -savedErrno;
}
-
- if (0 != TEMP_FAILURE_RETRY(bind(transportFd.fd.get(), addr.addr(), addr.addrSize()))) {
+ if (0 != TEMP_FAILURE_RETRY(bind(socket_fd.get(), addr.addr(), addr.addrSize()))) {
int savedErrno = errno;
ALOGE("Could not bind socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
return -savedErrno;
}
- // Right now, we create all threads at once, making accept4 slow. To avoid hanging the client,
- // the backlog is increased to a large number.
- // TODO(b/189955605): Once we create threads dynamically & lazily, the backlog can be reduced
- // to 1.
- if (0 != TEMP_FAILURE_RETRY(listen(transportFd.fd.get(), 50 /*backlog*/))) {
- int savedErrno = errno;
- ALOGE("Could not listen socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
- return -savedErrno;
- }
-
- LOG_RPC_DETAIL("Successfully setup socket server %s", addr.toString().c_str());
-
- if (status_t status = setupExternalServer(std::move(transportFd.fd)); status != OK) {
- ALOGE("Another thread has set up server while calling setupSocketServer. Race?");
- return status;
- }
- return OK;
+ return setupRawSocketServer(std::move(socket_fd));
}
-status_t RpcServer::setupRawSocketServer(base::unique_fd socket_fd) {
+status_t RpcServer::setupRawSocketServer(unique_fd socket_fd) {
LOG_ALWAYS_FATAL_IF(!socket_fd.ok(), "Socket must be setup to listen.");
- RpcTransportFd transportFd(std::move(socket_fd));
// Right now, we create all threads at once, making accept4 slow. To avoid hanging the client,
// the backlog is increased to a large number.
// TODO(b/189955605): Once we create threads dynamically & lazily, the backlog can be reduced
// to 1.
- if (0 != TEMP_FAILURE_RETRY(listen(transportFd.fd.get(), 50 /*backlog*/))) {
+ if (0 != TEMP_FAILURE_RETRY(listen(socket_fd.get(), 50 /*backlog*/))) {
int savedErrno = errno;
ALOGE("Could not listen initialized Unix socket: %s", strerror(savedErrno));
return -savedErrno;
}
- if (status_t status = setupExternalServer(std::move(transportFd.fd)); status != OK) {
+ if (status_t status = setupExternalServer(std::move(socket_fd)); status != OK) {
ALOGE("Another thread has set up server while calling setupSocketServer. Race?");
return status;
}
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 6de6ce8..f730acb 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -150,6 +150,9 @@
// Returns Status(EX_BAD_PARCELABLE) when the Parcel is not consumed.
binder::Status enforceNoDataAvail() const;
+ // This Api is used by fuzzers to skip dataAvail checks.
+ void setEnforceNoDataAvail(bool enforceNoDataAvail);
+
void freeData();
size_t objectsCount() const;
@@ -1329,6 +1332,9 @@
// data to be overridden with zero when deallocated
mutable bool mDeallocZero;
+ // Set this to false to skip dataAvail checks.
+ bool mEnforceNoDataAvail;
+
release_func mOwner;
size_t mReserved;
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index c320e8d..8693022 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -129,7 +129,13 @@
}
T* array;
- if (!allocator(arrayData, length, &array)) return STATUS_NO_MEMORY;
+ if (!allocator(arrayData, length, &array)) {
+ if (length < 0) {
+ return STATUS_UNEXPECTED_NULL;
+ } else {
+ return STATUS_NO_MEMORY;
+ }
+ }
if (length <= 0) return STATUS_OK;
if (array == nullptr) return STATUS_NO_MEMORY;
@@ -157,7 +163,13 @@
}
char16_t* array;
- if (!allocator(arrayData, length, &array)) return STATUS_NO_MEMORY;
+ if (!allocator(arrayData, length, &array)) {
+ if (length < 0) {
+ return STATUS_UNEXPECTED_NULL;
+ } else {
+ return STATUS_NO_MEMORY;
+ }
+ }
if (length <= 0) return STATUS_OK;
if (array == nullptr) return STATUS_NO_MEMORY;
@@ -204,7 +216,13 @@
return status;
}
- if (!allocator(arrayData, length)) return STATUS_NO_MEMORY;
+ if (!allocator(arrayData, length)) {
+ if (length < 0) {
+ return STATUS_UNEXPECTED_NULL;
+ } else {
+ return STATUS_NO_MEMORY;
+ }
+ }
if (length <= 0) return STATUS_OK;
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index 4e10fa9..ca2cedc 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -502,7 +502,7 @@
let instances = binder::get_declared_instances("android.hardware.light.ILights")
.expect("Could not get declared instances");
- let expected_defaults = if has_lights { 1 } else { 0 };
+ let expected_defaults = usize::from(has_lights);
assert_eq!(expected_defaults, instances.iter().filter(|i| i.as_str() == "default").count());
}
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 03e4a23..a999d59 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -723,5 +723,7 @@
"smoreland@google.com",
"waghpawan@google.com",
],
+ // Adds bugs to hotlist "AIDL fuzzers bugs" on buganizer
+ hotlists: ["4637097"],
},
}
diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
index 25f6096..86461c8 100644
--- a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
+++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
@@ -18,6 +18,7 @@
#include <fuzzbinder/random_parcel.h>
#include <android-base/logging.h>
+#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
namespace android {
@@ -30,10 +31,17 @@
.extraFds = {},
};
+ if (provider.ConsumeBool()) {
+ // set calling uid
+ IPCThreadState::self()->restoreCallingIdentity(provider.ConsumeIntegral<int64_t>());
+ }
+
while (provider.remaining_bytes() > 0) {
uint32_t code = provider.ConsumeIntegral<uint32_t>();
uint32_t flags = provider.ConsumeIntegral<uint32_t>();
Parcel data;
+ // for increased fuzz coverage
+ data.setEnforceNoDataAvail(provider.ConsumeBool());
sp<IBinder> target = options.extraBinders.at(
provider.ConsumeIntegralInRange<size_t>(0, options.extraBinders.size() - 1));
@@ -50,6 +58,8 @@
fillRandomParcel(&data, FuzzedDataProvider(subData.data(), subData.size()), &options);
Parcel reply;
+ // for increased fuzz coverage
+ reply.setEnforceNoDataAvail(provider.ConsumeBool());
(void)target->transact(code, data, &reply, flags);
// feed back in binders and fds that are returned from the service, so that
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 924e65e..95962af 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -24,10 +24,31 @@
#include <binder/Parcel.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/LayerState.h>
+#include <gui/SurfaceControl.h>
#include <private/gui/ParcelUtils.h>
#include <system/window.h>
#include <utils/Errors.h>
+#define CHECK_DIFF(DIFF_RESULT, CHANGE_FLAG, OTHER, FIELD) \
+ { \
+ if ((OTHER.what & CHANGE_FLAG) && (FIELD != OTHER.FIELD)) { \
+ DIFF_RESULT |= CHANGE_FLAG; \
+ } \
+ }
+
+#define CHECK_DIFF2(DIFF_RESULT, CHANGE_FLAG, OTHER, FIELD1, FIELD2) \
+ { \
+ CHECK_DIFF(DIFF_RESULT, CHANGE_FLAG, OTHER, FIELD1) \
+ CHECK_DIFF(DIFF_RESULT, CHANGE_FLAG, OTHER, FIELD2) \
+ }
+
+#define CHECK_DIFF3(DIFF_RESULT, CHANGE_FLAG, OTHER, FIELD1, FIELD2, FIELD3) \
+ { \
+ CHECK_DIFF(DIFF_RESULT, CHANGE_FLAG, OTHER, FIELD1) \
+ CHECK_DIFF(DIFF_RESULT, CHANGE_FLAG, OTHER, FIELD2) \
+ CHECK_DIFF(DIFF_RESULT, CHANGE_FLAG, OTHER, FIELD3) \
+ }
+
namespace android {
using gui::FocusRequest;
@@ -626,6 +647,74 @@
}
}
+uint64_t layer_state_t::diff(const layer_state_t& other) const {
+ uint64_t diff = 0;
+ CHECK_DIFF2(diff, ePositionChanged, other, x, y);
+ if (other.what & eLayerChanged) {
+ diff |= eLayerChanged;
+ diff &= ~eRelativeLayerChanged;
+ }
+ CHECK_DIFF(diff, eAlphaChanged, other, color.a);
+ CHECK_DIFF(diff, eMatrixChanged, other, matrix);
+ if (other.what & eTransparentRegionChanged &&
+ (!transparentRegion.hasSameRects(other.transparentRegion))) {
+ diff |= eTransparentRegionChanged;
+ }
+ if (other.what & eFlagsChanged) {
+ uint64_t changedFlags = (flags & other.mask) ^ (other.flags & other.mask);
+ if (changedFlags) diff |= eFlagsChanged;
+ }
+ CHECK_DIFF(diff, eLayerStackChanged, other, layerStack);
+ CHECK_DIFF(diff, eCornerRadiusChanged, other, cornerRadius);
+ CHECK_DIFF(diff, eBackgroundBlurRadiusChanged, other, backgroundBlurRadius);
+ if (other.what & eBlurRegionsChanged) diff |= eBlurRegionsChanged;
+ if (other.what & eRelativeLayerChanged) {
+ diff |= eRelativeLayerChanged;
+ diff &= ~eLayerChanged;
+ }
+ if (other.what & eReparent &&
+ !SurfaceControl::isSameSurface(parentSurfaceControlForChild,
+ other.parentSurfaceControlForChild)) {
+ diff |= eReparent;
+ }
+ CHECK_DIFF(diff, eBufferTransformChanged, other, bufferTransform);
+ CHECK_DIFF(diff, eTransformToDisplayInverseChanged, other, transformToDisplayInverse);
+ CHECK_DIFF(diff, eCropChanged, other, crop);
+ if (other.what & eBufferChanged) diff |= eBufferChanged;
+ CHECK_DIFF(diff, eDataspaceChanged, other, dataspace);
+ CHECK_DIFF(diff, eHdrMetadataChanged, other, hdrMetadata);
+ if (other.what & eSurfaceDamageRegionChanged &&
+ (!surfaceDamageRegion.hasSameRects(other.surfaceDamageRegion))) {
+ diff |= eSurfaceDamageRegionChanged;
+ }
+ CHECK_DIFF(diff, eApiChanged, other, api);
+ if (other.what & eSidebandStreamChanged) diff |= eSidebandStreamChanged;
+ CHECK_DIFF(diff, eApiChanged, other, api);
+ CHECK_DIFF(diff, eColorTransformChanged, other, colorTransform);
+ if (other.what & eHasListenerCallbacksChanged) diff |= eHasListenerCallbacksChanged;
+ if (other.what & eInputInfoChanged) diff |= eInputInfoChanged;
+ CHECK_DIFF3(diff, eBackgroundColorChanged, other, color.rgb, bgColorAlpha, bgColorDataspace);
+ if (other.what & eMetadataChanged) diff |= eMetadataChanged;
+ CHECK_DIFF(diff, eShadowRadiusChanged, other, shadowRadius);
+ CHECK_DIFF3(diff, eRenderBorderChanged, other, borderEnabled, borderWidth, borderColor);
+ CHECK_DIFF(diff, eDefaultFrameRateCompatibilityChanged, other, defaultFrameRateCompatibility);
+ CHECK_DIFF(diff, eFrameRateSelectionPriority, other, frameRateSelectionPriority);
+ CHECK_DIFF3(diff, eFrameRateChanged, other, frameRate, frameRateCompatibility,
+ changeFrameRateStrategy);
+ CHECK_DIFF(diff, eFixedTransformHintChanged, other, fixedTransformHint);
+ CHECK_DIFF(diff, eAutoRefreshChanged, other, autoRefresh);
+ CHECK_DIFF(diff, eTrustedOverlayChanged, other, isTrustedOverlay);
+ CHECK_DIFF(diff, eStretchChanged, other, stretchEffect);
+ CHECK_DIFF(diff, eBufferCropChanged, other, bufferCrop);
+ CHECK_DIFF(diff, eDestinationFrameChanged, other, destinationFrame);
+ if (other.what & eProducerDisconnect) diff |= eProducerDisconnect;
+ CHECK_DIFF(diff, eDropInputModeChanged, other, dropInputMode);
+ CHECK_DIFF(diff, eColorChanged, other, color.rgb);
+ CHECK_DIFF(diff, eColorSpaceAgnosticChanged, other, colorSpaceAgnostic);
+ CHECK_DIFF(diff, eDimmingEnabledChanged, other, dimmingEnabled);
+ return diff;
+}
+
bool layer_state_t::hasBufferChanges() const {
return what & layer_state_t::eBufferChanged;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index d18d22d..1e43700 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1250,6 +1250,7 @@
if ((mask & layer_state_t::eLayerOpaque) || (mask & layer_state_t::eLayerHidden) ||
(mask & layer_state_t::eLayerSecure) || (mask & layer_state_t::eLayerSkipScreenshot) ||
(mask & layer_state_t::eEnableBackpressure) ||
+ (mask & layer_state_t::eIgnoreDestinationFrame) ||
(mask & layer_state_t::eLayerIsDisplayDecoration)) {
s->what |= layer_state_t::eFlagsChanged;
}
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 09f171d..6ec6bd7 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -201,7 +201,32 @@
void merge(const layer_state_t& other);
status_t write(Parcel& output) const;
status_t read(const Parcel& input);
+ // Compares two layer_state_t structs and returns a set of change flags describing all the
+ // states that are different.
+ uint64_t diff(const layer_state_t& other) const;
bool hasBufferChanges() const;
+
+ // Changes to the tree structure.
+ static constexpr uint64_t HIERARCHY_CHANGES = layer_state_t::eLayerChanged |
+ layer_state_t::eRelativeLayerChanged | layer_state_t::eReparent |
+ layer_state_t::eBackgroundColorChanged;
+ // Content updates.
+ static constexpr uint64_t CONTENT_CHANGES = layer_state_t::eAlphaChanged |
+ layer_state_t::eTransparentRegionChanged | layer_state_t::eShadowRadiusChanged |
+ layer_state_t::eRenderBorderChanged | layer_state_t::eColorChanged |
+ layer_state_t::eBufferChanged | layer_state_t::eDataspaceChanged |
+ layer_state_t::eApiChanged | layer_state_t::eSidebandStreamChanged |
+ layer_state_t::eColorTransformChanged | layer_state_t::eCornerRadiusChanged |
+ layer_state_t::eBackgroundColorChanged | layer_state_t::eColorSpaceAgnosticChanged |
+ layer_state_t::eBackgroundBlurRadiusChanged | layer_state_t::eBlurRegionsChanged |
+ layer_state_t::eAutoRefreshChanged | layer_state_t::eStretchChanged;
+ // Changes to content or children size.
+ static constexpr uint64_t GEOMETRY_CHANGES = layer_state_t::ePositionChanged |
+ layer_state_t::eMatrixChanged | layer_state_t::eTransparentRegionChanged |
+ layer_state_t::eBufferCropChanged | layer_state_t::eBufferTransformChanged |
+ layer_state_t::eTransformToDisplayInverseChanged | layer_state_t::eCropChanged |
+ layer_state_t::eDestinationFrameChanged;
+
bool hasValidBuffer() const;
void sanitize(int32_t permissions);
@@ -212,6 +237,11 @@
float dsdy{0};
status_t write(Parcel& output) const;
status_t read(const Parcel& input);
+ inline bool operator==(const matrix22_t& other) const {
+ return std::tie(dsdx, dtdx, dtdy, dsdy) ==
+ std::tie(other.dsdx, other.dtdx, other.dtdy, other.dsdy);
+ }
+ inline bool operator!=(const matrix22_t& other) const { return !(*this == other); }
};
sp<IBinder> surface;
int32_t layerId;
diff --git a/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymapmath.h b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymapmath.h
index ef9112e..e76bc20 100644
--- a/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymapmath.h
+++ b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymapmath.h
@@ -23,6 +23,9 @@
namespace android::recoverymap {
+////////////////////////////////////////////////////////////////////////////////
+// Framework
+
const float kSdrWhiteNits = 100.0f;
struct Color {
@@ -40,35 +43,142 @@
};
};
-/*
- * Convert from OETF'd bt.2100 RGB to YUV, according to BT.2100
- */
-Color bt2100RgbToYuv(Color e);
+inline Color operator+=(Color& lhs, const Color& rhs) {
+ lhs.r += rhs.r;
+ lhs.g += rhs.g;
+ lhs.b += rhs.b;
+ return lhs;
+}
+inline Color operator-=(Color& lhs, const Color& rhs) {
+ lhs.r -= rhs.r;
+ lhs.g -= rhs.g;
+ lhs.b -= rhs.b;
+ return lhs;
+}
+
+inline Color operator+(const Color& lhs, const Color& rhs) {
+ Color temp = lhs;
+ return temp += rhs;
+}
+inline Color operator-(const Color& lhs, const Color& rhs) {
+ Color temp = lhs;
+ return temp -= rhs;
+}
+
+inline Color operator+=(Color& lhs, const float rhs) {
+ lhs.r += rhs;
+ lhs.g += rhs;
+ lhs.b += rhs;
+ return lhs;
+}
+inline Color operator-=(Color& lhs, const float rhs) {
+ lhs.r -= rhs;
+ lhs.g -= rhs;
+ lhs.b -= rhs;
+ return lhs;
+}
+inline Color operator*=(Color& lhs, const float rhs) {
+ lhs.r *= rhs;
+ lhs.g *= rhs;
+ lhs.b *= rhs;
+ return lhs;
+}
+inline Color operator/=(Color& lhs, const float rhs) {
+ lhs.r /= rhs;
+ lhs.g /= rhs;
+ lhs.b /= rhs;
+ return lhs;
+}
+
+inline Color operator+(const Color& lhs, const float rhs) {
+ Color temp = lhs;
+ return temp += rhs;
+}
+inline Color operator-(const Color& lhs, const float rhs) {
+ Color temp = lhs;
+ return temp -= rhs;
+}
+inline Color operator*(const Color& lhs, const float rhs) {
+ Color temp = lhs;
+ return temp *= rhs;
+}
+inline Color operator/(const Color& lhs, const float rhs) {
+ Color temp = lhs;
+ return temp /= rhs;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// sRGB transformations
/*
- * Convert srgb YUV to RGB, according to ECMA TR/98.
+ * Calculate the luminance of a linear RGB sRGB pixel, according to IEC 61966-2-1.
*/
-Color srgbYuvToRgb(Color e);
+float srgbLuminance(Color e);
/*
- * TODO: better source for srgb transfer function
- * Convert from srgb to linear, according to https://en.wikipedia.org/wiki/SRGB.
+ * Convert from OETF'd srgb YUV to RGB, according to ECMA TR/98.
+ */
+Color srgbYuvToRgb(Color e_gamma);
+
+/*
+ * Convert from OETF'd srgb RGB to YUV, according to ECMA TR/98.
+ */
+Color srgbRgbToYuv(Color e_gamma);
+
+/*
+ * Convert from srgb to linear, according to IEC 61966-2-1.
+ *
* [0.0, 1.0] range in and out.
*/
-float srgbInvOetf(float e);
-Color srgbInvOetf(Color e);
+float srgbInvOetf(float e_gamma);
+Color srgbInvOetf(Color e_gamma);
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Display-P3 transformations
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// BT.2100 transformations - according to ITU-R BT.2100-2
/*
- * Convert from HLG to scene luminance in nits, according to BT.2100.
+ * Calculate the luminance of a linear RGB BT.2100 pixel.
*/
-float hlgInvOetf(float e);
+float bt2100Luminance(Color e);
/*
- * Convert from scene luminance in nits to HLG, according to BT.2100.
+ * Convert from OETF'd BT.2100 RGB to YUV.
+ */
+Color bt2100RgbToYuv(Color e_gamma);
+
+/*
+ * Convert from OETF'd BT.2100 YUV to RGB.
+ */
+Color bt2100YuvToRgb(Color e_gamma);
+
+/*
+ * Convert from scene luminance in nits to HLG.
*/
Color hlgOetf(Color e);
/*
+ * Convert from HLG to scene luminance in nits.
+ */
+Color hlgInvOetf(Color e_gamma);
+
+////////////////////////////////////////////////////////////////////////////////
+// Color space conversions
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Recovery map calculations
+
+/*
* Calculate the 8-bit unsigned integer recovery value for the given SDR and HDR
* luminances in linear space, and the hdr ratio to encode against.
*/
@@ -86,6 +196,11 @@
Color getYuv420Pixel(jr_uncompressed_ptr image, size_t x, size_t y);
/*
+ * Helper for sampling from images.
+ */
+Color getP010Pixel(jr_uncompressed_ptr image, size_t x, size_t y);
+
+/*
* Sample the recovery value for the map from a given x,y coordinate on a scale
* that is map scale factor larger than the map size.
*/
@@ -97,8 +212,13 @@
*
* Expect narrow-range image data for P010.
*/
-float sampleYuv420Y(jr_uncompressed_ptr map, size_t map_scale_factor, size_t x, size_t y);
-float sampleP010Y(jr_uncompressed_ptr map, size_t map_scale_factor, size_t x, size_t y);
+Color sampleYuv420(jr_uncompressed_ptr map, size_t map_scale_factor, size_t x, size_t y);
+
+/*
+ * Sample the image Y value at the provided location, with a weighting based on nearby pixels
+ * and the map scale factor. Assumes narrow-range image data for P010.
+ */
+Color sampleP010(jr_uncompressed_ptr map, size_t map_scale_factor, size_t x, size_t y);
} // namespace android::recoverymap
diff --git a/libs/jpegrecoverymap/recoverymap.cpp b/libs/jpegrecoverymap/recoverymap.cpp
index bd16a68..86eb8a8 100644
--- a/libs/jpegrecoverymap/recoverymap.cpp
+++ b/libs/jpegrecoverymap/recoverymap.cpp
@@ -301,31 +301,38 @@
std::unique_ptr<uint8_t[]> map_data;
map_data.reset(reinterpret_cast<uint8_t*>(dest->data));
- uint16_t yp_hdr_max = 0;
+ float hdr_y_nits_max = 0.0f;
for (size_t y = 0; y < image_height; ++y) {
for (size_t x = 0; x < image_width; ++x) {
- size_t pixel_idx = x + y * image_width;
- uint16_t yp_hdr = reinterpret_cast<uint8_t*>(uncompressed_yuv_420_image->data)[pixel_idx];
- if (yp_hdr > yp_hdr_max) {
- yp_hdr_max = yp_hdr;
+ Color hdr_yuv_gamma = getP010Pixel(uncompressed_p010_image, x, y);
+ Color hdr_rgb_gamma = bt2100YuvToRgb(hdr_yuv_gamma);
+ Color hdr_rgb = hlgInvOetf(hdr_rgb_gamma);
+ float hdr_y_nits = bt2100Luminance(hdr_rgb);
+
+ if (hdr_y_nits > hdr_y_nits_max) {
+ hdr_y_nits_max = hdr_y_nits;
}
}
}
- float y_hdr_max_nits = hlgInvOetf(yp_hdr_max);
- hdr_ratio = y_hdr_max_nits / kSdrWhiteNits;
+ hdr_ratio = hdr_y_nits_max / kSdrWhiteNits;
for (size_t y = 0; y < map_height; ++y) {
for (size_t x = 0; x < map_width; ++x) {
- float yp_sdr = sampleYuv420Y(uncompressed_yuv_420_image, kMapDimensionScaleFactor, x, y);
- float yp_hdr = sampleP010Y(uncompressed_p010_image, kMapDimensionScaleFactor, x, y);
+ Color sdr_yuv_gamma = sampleYuv420(uncompressed_yuv_420_image,
+ kMapDimensionScaleFactor, x, y);
+ Color sdr_rgb_gamma = srgbYuvToRgb(sdr_yuv_gamma);
+ Color sdr_rgb = srgbInvOetf(sdr_rgb_gamma);
+ float sdr_y_nits = srgbLuminance(sdr_rgb);
- float y_sdr_nits = srgbInvOetf(yp_sdr);
- float y_hdr_nits = hlgInvOetf(yp_hdr);
+ Color hdr_yuv_gamma = sampleP010(uncompressed_p010_image, kMapDimensionScaleFactor, x, y);
+ Color hdr_rgb_gamma = bt2100YuvToRgb(hdr_yuv_gamma);
+ Color hdr_rgb = hlgInvOetf(hdr_rgb_gamma);
+ float hdr_y_nits = bt2100Luminance(hdr_rgb);
size_t pixel_idx = x + y * map_width;
reinterpret_cast<uint8_t*>(dest->data)[pixel_idx] =
- encodeRecovery(y_sdr_nits, y_hdr_nits, hdr_ratio);
+ encodeRecovery(sdr_y_nits, hdr_y_nits, hdr_ratio);
}
}
@@ -367,7 +374,8 @@
Color rgb_hdr = applyRecovery(rgb_sdr, recovery, hdr_ratio);
Color rgbp_hdr = hlgOetf(rgb_hdr);
- Color ypuv_hdr = bt2100RgbToYuv(rgbp_hdr);
+ // TODO: actually just leave in RGB and convert to RGBA1010102 instead.
+ Color ypuv_hdr = srgbRgbToYuv(rgbp_hdr);
reinterpret_cast<uint16_t*>(dest->data)[pixel_y_idx] = ypuv_hdr.r;
reinterpret_cast<uint16_t*>(dest->data)[pixel_count + pixel_uv_idx] = ypuv_hdr.g;
diff --git a/libs/jpegrecoverymap/recoverymapmath.cpp b/libs/jpegrecoverymap/recoverymapmath.cpp
index 368783f..0d3319f 100644
--- a/libs/jpegrecoverymap/recoverymapmath.cpp
+++ b/libs/jpegrecoverymap/recoverymapmath.cpp
@@ -20,42 +20,102 @@
namespace android::recoverymap {
-static const float kBt2100R = 0.2627f, kBt2100G = 0.6780f, kBt2100B = 0.0593f;
-static const float kBt2100Cb = 1.8814f, kBt2100Cr = 1.4746f;
+////////////////////////////////////////////////////////////////////////////////
+// sRGB transformations
-Color bt2100RgbToYuv(Color e) {
- float yp = kBt2100R * e.r + kBt2100G * e.g + kBt2100B * e.b;
- return {{{yp, (e.b - yp) / kBt2100Cb, (e.r - yp) / kBt2100Cr }}};
+static const float kSrgbR = 0.299f, kSrgbG = 0.587f, kSrgbB = 0.114f;
+
+float srgbLuminance(Color e) {
+ return kSrgbR * e.r + kSrgbG * e.g + kSrgbB * e.b;
}
static const float kSrgbRCr = 1.402f, kSrgbGCb = 0.34414f, kSrgbGCr = 0.71414f, kSrgbBCb = 1.772f;
-Color srgbYuvToRgb(Color e) {
- return {{{ e.y + kSrgbRCr * e.v, e.y - kSrgbGCb * e.u - kSrgbGCr * e.v, e.y + kSrgbBCb * e.u }}};
+Color srgbYuvToRgb(Color e_gamma) {
+ return {{{ e_gamma.y + kSrgbRCr * e_gamma.v,
+ e_gamma.y - kSrgbGCb * e_gamma.u - kSrgbGCr * e_gamma.v,
+ e_gamma.y + kSrgbBCb * e_gamma.u }}};
}
-float srgbInvOetf(float e) {
- if (e <= 0.04045f) {
- return e / 12.92f;
+static const float kSrgbUR = -0.1687f, kSrgbUG = -0.3313f, kSrgbUB = 0.5f;
+static const float kSrgbVR = 0.5f, kSrgbVG = -0.4187f, kSrgbVB = -0.0813f;
+
+Color srgbRgbToYuv(Color e_gamma) {
+ return {{{ kSrgbR * e_gamma.r + kSrgbG * e_gamma.g + kSrgbB * e_gamma.b,
+ kSrgbUR * e_gamma.r + kSrgbUG * e_gamma.g + kSrgbUB * e_gamma.b,
+ kSrgbVR * e_gamma.r + kSrgbVG * e_gamma.g + kSrgbVB * e_gamma.b }}};
+}
+
+float srgbInvOetf(float e_gamma) {
+ if (e_gamma <= 0.04045f) {
+ return e_gamma / 12.92f;
} else {
- return pow((e + 0.055f) / 1.055f, 2.4);
+ return pow((e_gamma + 0.055f) / 1.055f, 2.4);
}
}
-Color srgbInvOetf(Color e) {
- return {{{ srgbInvOetf(e.r), srgbInvOetf(e.g), srgbInvOetf(e.b) }}};
+Color srgbInvOetf(Color e_gamma) {
+ return {{{ srgbInvOetf(e_gamma.r),
+ srgbInvOetf(e_gamma.g),
+ srgbInvOetf(e_gamma.b) }}};
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Display-P3 transformations
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// BT.2100 transformations - according to ITU-R BT.2100-2
+
+static const float kBt2100R = 0.2627f, kBt2100G = 0.6780f, kBt2100B = 0.0593f;
+
+float bt2100Luminance(Color e) {
+ return kBt2100R * e.r + kBt2100G * e.g + kBt2100B * e.b;
+}
+
+static const float kBt2100Cb = 1.8814f, kBt2100Cr = 1.4746f;
+
+Color bt2100RgbToYuv(Color e_gamma) {
+ float y_gamma = bt2100Luminance(e_gamma);
+ return {{{ y_gamma,
+ (e_gamma.b - y_gamma) / kBt2100Cb,
+ (e_gamma.r - y_gamma) / kBt2100Cr }}};
+}
+
+// Derived from the reverse of bt2100RgbToYuv. The derivation for R and B are
+// pretty straight forward; we just reverse the formulas for U and V above. But
+// deriving the formula for G is a bit more complicated:
+//
+// Start with equation for luminance:
+// Y = kBt2100R * R + kBt2100G * G + kBt2100B * B
+// Solve for G:
+// G = (Y - kBt2100R * R - kBt2100B * B) / kBt2100B
+// Substitute equations for R and B in terms YUV:
+// G = (Y - kBt2100R * (Y + kBt2100Cr * V) - kBt2100B * (Y + kBt2100Cb * U)) / kBt2100B
+// Simplify:
+// G = Y * ((1 - kBt2100R - kBt2100B) / kBt2100G)
+// + U * (kBt2100B * kBt2100Cb / kBt2100G)
+// + V * (kBt2100R * kBt2100Cr / kBt2100G)
+//
+// We then get the following coeficients for calculating G from YUV:
+//
+// Coef for Y = (1 - kBt2100R - kBt2100B) / kBt2100G = 1
+// Coef for U = kBt2100B * kBt2100Cb / kBt2100G = kBt2100GCb = ~0.1645
+// Coef for V = kBt2100R * kBt2100Cr / kBt2100G = kBt2100GCr = ~0.5713
+
+static const float kBt2100GCb = kBt2100B * kBt2100Cb / kBt2100G;
+static const float kBt2100GCr = kBt2100R * kBt2100Cr / kBt2100G;
+
+Color bt2100YuvToRgb(Color e_gamma) {
+ return {{{ e_gamma.y + kBt2100Cr * e_gamma.v,
+ e_gamma.y - kBt2100GCb * e_gamma.u - kBt2100GCr * e_gamma.v,
+ e_gamma.y + kBt2100Cb * e_gamma.u }}};
}
static const float kHlgA = 0.17883277f, kHlgB = 0.28466892f, kHlgC = 0.55991073;
-float hlgInvOetf(float e) {
- if (e <= 0.5f) {
- return pow(e, 2.0f) / 3.0f;
- } else {
- return (exp((e - kHlgC) / kHlgA) + kHlgB) / 12.0f;
- }
-}
-
static float hlgOetf(float e) {
if (e <= 1.0f/12.0f) {
return sqrt(3.0f * e);
@@ -68,6 +128,28 @@
return {{{ hlgOetf(e.r), hlgOetf(e.g), hlgOetf(e.b) }}};
}
+float hlgInvOetf(float e_gamma) {
+ if (e_gamma <= 0.5f) {
+ return pow(e_gamma, 2.0f) / 3.0f;
+ } else {
+ return (exp((e_gamma - kHlgC) / kHlgA) + kHlgB) / 12.0f;
+ }
+}
+
+Color hlgInvOetf(Color e_gamma) {
+ return {{{ hlgInvOetf(e_gamma.r),
+ hlgInvOetf(e_gamma.g),
+ hlgInvOetf(e_gamma.b) }}};
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Color conversions
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Recovery map calculations
+
uint8_t encodeRecovery(float y_sdr, float y_hdr, float hdr_ratio) {
float gain = 1.0f;
if (y_sdr > 0.0f) {
@@ -137,40 +219,42 @@
(static_cast<float>(v_uint) - 128.0f) / 255.0f }}};
}
-typedef float (*sampleComponentFn)(jr_uncompressed_ptr, size_t, size_t);
+Color getP010Pixel(jr_uncompressed_ptr image, size_t x, size_t y) {
+ size_t pixel_count = image->width * image->height;
-static float sampleComponent(jr_uncompressed_ptr image, size_t map_scale_factor, size_t x, size_t y,
- sampleComponentFn sample_fn) {
- float e = 0.0f;
+ size_t pixel_y_idx = x + y * image->width;
+ size_t pixel_uv_idx = x / 2 + (y / 2) * (image->width / 2);
+
+ uint16_t y_uint = reinterpret_cast<uint16_t*>(image->data)[pixel_y_idx];
+ uint16_t u_uint = reinterpret_cast<uint16_t*>(image->data)[pixel_count + pixel_uv_idx * 2];
+ uint16_t v_uint = reinterpret_cast<uint16_t*>(image->data)[pixel_count + pixel_uv_idx * 2 + 1];
+
+ // Conversions include taking narrow-range into account.
+ return {{{ static_cast<float>(y_uint) / 940.0f,
+ (static_cast<float>(u_uint) - 64.0f) / 940.0f - 0.5f,
+ (static_cast<float>(v_uint) - 64.0f) / 940.0f - 0.5f }}};
+}
+
+typedef Color (*getPixelFn)(jr_uncompressed_ptr, size_t, size_t);
+
+static Color samplePixels(jr_uncompressed_ptr image, size_t map_scale_factor, size_t x, size_t y,
+ getPixelFn get_pixel_fn) {
+ Color e = {{{ 0.0f, 0.0f, 0.0f }}};
for (size_t dy = 0; dy < map_scale_factor; ++dy) {
for (size_t dx = 0; dx < map_scale_factor; ++dx) {
- e += sample_fn(image, x * map_scale_factor + dx, y * map_scale_factor + dy);
+ e += get_pixel_fn(image, x * map_scale_factor + dx, y * map_scale_factor + dy);
}
}
return e / static_cast<float>(map_scale_factor * map_scale_factor);
}
-static float getYuv420Y(jr_uncompressed_ptr image, size_t x, size_t y) {
- size_t pixel_idx = x + y * image->width;
- uint8_t y_uint = reinterpret_cast<uint8_t*>(image->data)[pixel_idx];
- return static_cast<float>(y_uint) / 255.0f;
+Color sampleYuv420(jr_uncompressed_ptr image, size_t map_scale_factor, size_t x, size_t y) {
+ return samplePixels(image, map_scale_factor, x, y, getYuv420Pixel);
}
-
-float sampleYuv420Y(jr_uncompressed_ptr image, size_t map_scale_factor, size_t x, size_t y) {
- return sampleComponent(image, map_scale_factor, x, y, getYuv420Y);
-}
-
-static float getP010Y(jr_uncompressed_ptr image, size_t x, size_t y) {
- size_t pixel_idx = x + y * image->width;
- uint8_t y_uint = reinterpret_cast<uint16_t*>(image->data)[pixel_idx];
- // Expecting narrow range input
- return (static_cast<float>(y_uint) - 64.0f) / 960.0f;
-}
-
-float sampleP010Y(jr_uncompressed_ptr image, size_t map_scale_factor, size_t x, size_t y) {
- return sampleComponent(image, map_scale_factor, x, y, getP010Y);
+Color sampleP010(jr_uncompressed_ptr image, size_t map_scale_factor, size_t x, size_t y) {
+ return samplePixels(image, map_scale_factor, x, y, getP010Pixel);
}
} // namespace android::recoverymap
diff --git a/libs/jpegrecoverymap/tests/Android.bp b/libs/jpegrecoverymap/tests/Android.bp
index 41af991..8f37954 100644
--- a/libs/jpegrecoverymap/tests/Android.bp
+++ b/libs/jpegrecoverymap/tests/Android.bp
@@ -27,7 +27,15 @@
srcs: [
"recoverymap_test.cpp",
],
+ shared_libs: [
+ "libimage_io",
+ "libjpeg",
+ "liblog",
+ ],
static_libs: [
+ "libgtest",
+ "libjpegdecoder",
+ "libjpegencoder",
"libjpegrecoverymap",
],
}
diff --git a/libs/jpegrecoverymap/tests/recoverymap_test.cpp b/libs/jpegrecoverymap/tests/recoverymap_test.cpp
index c436138..226056b 100644
--- a/libs/jpegrecoverymap/tests/recoverymap_test.cpp
+++ b/libs/jpegrecoverymap/tests/recoverymap_test.cpp
@@ -14,9 +14,33 @@
* limitations under the License.
*/
+#include <gtest/gtest.h>
#include <jpegrecoverymap/recoverymap.h>
-namespace android {
+namespace android::recoverymap {
-// Add new tests here.
-} // namespace android
+class RecoveryMapTest : public testing::Test {
+public:
+ RecoveryMapTest();
+ ~RecoveryMapTest();
+protected:
+ virtual void SetUp();
+ virtual void TearDown();
+};
+
+RecoveryMapTest::RecoveryMapTest() {}
+RecoveryMapTest::~RecoveryMapTest() {}
+
+void RecoveryMapTest::SetUp() {}
+void RecoveryMapTest::TearDown() {}
+
+TEST_F(RecoveryMapTest, build) {
+ // Force all of the recovery map lib to be linked by calling all public functions.
+ RecoveryMap recovery_map;
+ recovery_map.encodeJPEGR(nullptr, nullptr, nullptr, 0, nullptr);
+ recovery_map.encodeJPEGR(nullptr, nullptr, nullptr, nullptr);
+ recovery_map.encodeJPEGR(nullptr, nullptr, nullptr);
+ recovery_map.decodeJPEGR(nullptr, nullptr, nullptr, false);
+}
+
+} // namespace android::recoverymap
diff --git a/services/inputflinger/TEST_MAPPING b/services/inputflinger/TEST_MAPPING
index 4a0f2ec..b3b4fb1 100644
--- a/services/inputflinger/TEST_MAPPING
+++ b/services/inputflinger/TEST_MAPPING
@@ -41,6 +41,7 @@
"include-filter": "android.view.cts.input",
"include-filter": "android.view.cts.MotionEventTest",
"include-filter": "android.view.cts.PointerCaptureTest",
+ "include-filter": "android.view.cts.TooltipTest",
"include-filter": "android.view.cts.VerifyInputEventTest"
}
]
@@ -128,6 +129,7 @@
{
"include-filter": "android.view.cts.MotionEventTest",
"include-filter": "android.view.cts.PointerCaptureTest",
+ "include-filter": "android.view.cts.TooltipTest",
"include-filter": "android.view.cts.VerifyInputEventTest"
}
]
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 87a4ff4..eb938c8 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -1769,15 +1769,16 @@
void InputDispatcher::logOutboundMotionDetails(const char* prefix, const MotionEntry& entry) {
if (DEBUG_OUTBOUND_EVENT_DETAILS) {
- ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32
+ ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=%s, displayId=%" PRId32
", policyFlags=0x%x, "
"action=%s, actionButton=0x%x, flags=0x%x, "
"metaState=0x%x, buttonState=0x%x,"
"edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64,
- prefix, entry.eventTime, entry.deviceId, entry.source, entry.displayId,
- entry.policyFlags, MotionEvent::actionToString(entry.action).c_str(),
- entry.actionButton, entry.flags, entry.metaState, entry.buttonState, entry.edgeFlags,
- entry.xPrecision, entry.yPrecision, entry.downTime);
+ prefix, entry.eventTime, entry.deviceId,
+ inputEventSourceToString(entry.source).c_str(), entry.displayId, entry.policyFlags,
+ MotionEvent::actionToString(entry.action).c_str(), entry.actionButton, entry.flags,
+ entry.metaState, entry.buttonState, entry.edgeFlags, entry.xPrecision,
+ entry.yPrecision, entry.downTime);
for (uint32_t i = 0; i < entry.pointerCount; i++) {
ALOGD(" Pointer %d: id=%d, toolType=%d, "
@@ -2502,6 +2503,10 @@
}
}
+ if (tempTouchState.windows.empty()) {
+ mTouchStatesByDisplay.erase(displayId);
+ }
+
// Update hover state.
mLastHoverWindowHandle = newHoverWindowHandle;
diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp
index ee7da93..114e0bf 100644
--- a/services/inputflinger/dispatcher/TouchState.cpp
+++ b/services/inputflinger/dispatcher/TouchState.cpp
@@ -148,7 +148,8 @@
std::string TouchState::dump() const {
std::string out;
- out += StringPrintf("deviceId=%d, source=0x%08x\n", deviceId, source);
+ out += StringPrintf("deviceId=%d, source=%s\n", deviceId,
+ inputEventSourceToString(source).c_str());
if (!windows.empty()) {
out += " Windows:\n";
for (size_t i = 0; i < windows.size(); i++) {
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index 5657d61..a1a2af9 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -300,10 +300,11 @@
mCursorScrollAccumulator.process(rawEvent);
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
- const nsecs_t eventTime =
+ const auto [eventTime, readTime] =
applyBluetoothTimestampSmoothening(getDeviceContext().getDeviceIdentifier(),
- rawEvent->when, mLastEventTime);
- out += sync(eventTime, rawEvent->readTime);
+ rawEvent->when, rawEvent->readTime,
+ mLastEventTime);
+ out += sync(eventTime, readTime);
mLastEventTime = eventTime;
}
return out;
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
index ccff353..b193dff 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
@@ -119,6 +119,18 @@
if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
}
+ } else if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS && !mStylusMtToolSeen) {
+ mStylusMtToolSeen = true;
+ // The multi-touch device produced a stylus event with MT_TOOL_PEN. Dynamically
+ // re-configure this input device so that we add SOURCE_STYLUS if we haven't already.
+ // This is to cover the case where we cannot reliably detect whether a multi-touch
+ // device will ever produce stylus events when it is initially being configured.
+ if (!isFromSource(mSource, AINPUT_SOURCE_STYLUS)) {
+ // Add the stylus source immediately so that it is included in any events generated
+ // before we have a chance to re-configure the device.
+ mSource |= AINPUT_SOURCE_STYLUS;
+ bumpGeneration();
+ }
}
if (shouldSimulateStylusWithTouch() &&
outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER) {
@@ -200,7 +212,8 @@
}
bool MultiTouchInputMapper::hasStylus() const {
- return mTouchButtonAccumulator.hasStylus() || shouldSimulateStylusWithTouch();
+ return mStylusMtToolSeen || mTouchButtonAccumulator.hasStylus() ||
+ shouldSimulateStylusWithTouch();
}
bool MultiTouchInputMapper::shouldSimulateStylusWithTouch() const {
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
index ddf9e80..5f8bccf 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
@@ -50,6 +50,8 @@
// Specifies the pointer id bits that are in use, and their associated tracking id.
BitSet32 mPointerIdBits;
int32_t mPointerTrackingIdMap[MAX_POINTER_ID + 1];
+
+ bool mStylusMtToolSeen{false};
};
} // namespace android
diff --git a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
index 0b7ff84..d8a4d34 100644
--- a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
+++ b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
@@ -110,10 +110,11 @@
// coordinates result in extremely large instantaneous velocities, which can negatively impact
// user experience. To avoid this, we augment the timestamps so that subsequent event timestamps
// differ by at least a minimum delta value.
-static nsecs_t applyBluetoothTimestampSmoothening(const InputDeviceIdentifier& identifier,
- nsecs_t currentEventTime, nsecs_t lastEventTime) {
+static std::tuple<nsecs_t /*eventTime*/, nsecs_t /*readTime*/> applyBluetoothTimestampSmoothening(
+ const InputDeviceIdentifier& identifier, nsecs_t currentEventTime, nsecs_t readTime,
+ nsecs_t lastEventTime) {
if (identifier.bus != BUS_BLUETOOTH) {
- return currentEventTime;
+ return {currentEventTime, readTime};
}
// Assume the fastest rate at which a Bluetooth touch device can report input events is one
@@ -123,8 +124,14 @@
// We define a maximum smoothing time delta so that we don't generate events too far into the
// future.
constexpr static nsecs_t MAX_BLUETOOTH_SMOOTHING_DELTA = ms2ns(32);
- return std::min(std::max(currentEventTime, lastEventTime + MIN_BLUETOOTH_TIMESTAMP_DELTA),
- currentEventTime + MAX_BLUETOOTH_SMOOTHING_DELTA);
+ const nsecs_t smoothenedEventTime =
+ std::min(std::max(currentEventTime, lastEventTime + MIN_BLUETOOTH_TIMESTAMP_DELTA),
+ currentEventTime + MAX_BLUETOOTH_SMOOTHING_DELTA);
+ // If we are modifying the event time, treat this event as a synthetically generated event for
+ // latency tracking purposes and use the event time as the read time (zero read latency).
+ const nsecs_t smoothenedReadTime =
+ smoothenedEventTime != currentEventTime ? currentEventTime : readTime;
+ return {smoothenedEventTime, smoothenedReadTime};
}
} // namespace android
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 380c3a5..5be694f 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -1467,8 +1467,9 @@
const RawState& last =
mRawStatesPending.size() == 1 ? mCurrentRawState : mRawStatesPending.rbegin()[1];
- next.when = applyBluetoothTimestampSmoothening(getDeviceContext().getDeviceIdentifier(), when,
- last.when);
+ std::tie(next.when, next.readTime) =
+ applyBluetoothTimestampSmoothening(getDeviceContext().getDeviceIdentifier(), when,
+ readTime, last.when);
// Assign pointer ids.
if (!mHavePointerIds) {
@@ -3762,15 +3763,12 @@
PointerCoords pointerCoords[MAX_POINTERS];
PointerProperties pointerProperties[MAX_POINTERS];
uint32_t pointerCount = 0;
- bool stylusToolFound = false;
while (!idBits.isEmpty()) {
uint32_t id = idBits.clearFirstMarkedBit();
uint32_t index = idToIndex[id];
pointerProperties[pointerCount].copyFrom(properties[index]);
pointerCoords[pointerCount].copyFrom(coords[index]);
- stylusToolFound |= isStylusToolType(pointerProperties[pointerCount].toolType);
-
if (changedId >= 0 && id == uint32_t(changedId)) {
action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
}
@@ -3802,12 +3800,6 @@
if (mDeviceMode == DeviceMode::POINTER) {
mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
}
- if (stylusToolFound) {
- // Dynamically add the stylus source when there's a stylus tool being used to cover the case
- // where we cannot reliably detect whether a multi-touch device will ever produce stylus
- // events when it is initially being configured.
- source |= AINPUT_SOURCE_STYLUS;
- }
const int32_t displayId = getAssociatedDisplayId().value_or(ADISPLAY_ID_NONE);
const int32_t deviceId = getDeviceId();
std::vector<TouchVideoFrame> frames = getDeviceContext().getVideoFrames();
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index aaf50ce..689fe5c 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -22,6 +22,7 @@
#include <android-base/thread_annotations.h>
#include <binder/Binder.h>
#include <fcntl.h>
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <input/Input.h>
#include <linux/input.h>
@@ -43,6 +44,7 @@
namespace android::inputdispatcher {
using namespace ftl::flag_operators;
+using testing::AllOf;
// An arbitrary time value.
static constexpr nsecs_t ARBITRARY_TIME = 1234;
@@ -102,6 +104,28 @@
<< MotionEvent::actionToString(receivedAction);
}
+MATCHER_P(WithMotionAction, action, "MotionEvent with specified action") {
+ bool matches = action == arg.getAction();
+ if (!matches) {
+ *result_listener << "expected action " << MotionEvent::actionToString(action)
+ << ", but got " << MotionEvent::actionToString(arg.getAction());
+ }
+ if (action == AMOTION_EVENT_ACTION_CANCEL) {
+ if (!matches) {
+ *result_listener << "; ";
+ }
+ *result_listener << "expected FLAG_CANCELED to be set with ACTION_CANCEL, but was not set";
+ matches &= (arg.getFlags() & AMOTION_EVENT_FLAG_CANCELED) != 0;
+ }
+ return matches;
+}
+
+MATCHER_P(WithSource, source, "InputEvent with specified source") {
+ *result_listener << "expected source " << inputEventSourceToString(source) << ", but got "
+ << inputEventSourceToString(arg.getSource());
+ return arg.getSource() == source;
+}
+
// --- FakeInputDispatcherPolicy ---
class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface {
@@ -1205,6 +1229,12 @@
mInputReceiver->consumeCaptureEvent(hasCapture);
}
+ void consumeMotionEvent(const ::testing::Matcher<MotionEvent>& matcher) {
+ MotionEvent* motionEvent = consumeMotion();
+ ASSERT_NE(nullptr, motionEvent) << "Did not get a motion event";
+ ASSERT_THAT(*motionEvent, matcher);
+ }
+
void consumeEvent(int32_t expectedEventType, int32_t expectedAction,
std::optional<int32_t> expectedDisplayId,
std::optional<int32_t> expectedFlags) {
@@ -2207,6 +2237,48 @@
ADISPLAY_ID_DEFAULT, 0 /* expectedFlag */);
}
+/**
+ * Inject a mouse hover event followed by a tap from touchscreen.
+ * In the current implementation, the tap does not cause a HOVER_EXIT event.
+ */
+TEST_F(InputDispatcherTest, MouseHoverAndTouchTap) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
+ window->setFrame(Rect(0, 0, 100, 100));
+
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+
+ // Inject a hover_move from mouse.
+ NotifyMotionArgs motionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE,
+ ADISPLAY_ID_DEFAULT, {{50, 50}});
+ motionArgs.xCursorPosition = 50;
+ motionArgs.yCursorPosition = 50;
+ mDispatcher->notifyMotion(&motionArgs);
+ ASSERT_NO_FATAL_FAILURE(
+ window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
+ WithSource(AINPUT_SOURCE_MOUSE))));
+ ASSERT_NO_FATAL_FAILURE(
+ window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
+ WithSource(AINPUT_SOURCE_MOUSE))));
+
+ // Tap on the window
+ motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {{10, 10}});
+ mDispatcher->notifyMotion(&motionArgs);
+ ASSERT_NO_FATAL_FAILURE(
+ window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
+ WithSource(AINPUT_SOURCE_TOUCHSCREEN))));
+
+ motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {{10, 10}});
+ mDispatcher->notifyMotion(&motionArgs);
+ ASSERT_NO_FATAL_FAILURE(
+ window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
+ WithSource(AINPUT_SOURCE_TOUCHSCREEN))));
+}
+
TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 5c5fc77..6b6d0bb 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -10788,11 +10788,12 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
}
-TEST_F(MultiTouchInputMapperTest, ToolTypeSource) {
+TEST_F(MultiTouchInputMapperTest, StylusSourceIsAddedDynamicallyFromToolType) {
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION | ID | SLOT | PRESSURE | TOOL_TYPE);
MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled());
// Even if the device supports reporting the ABS_MT_TOOL_TYPE axis, which could give it the
// ability to report MT_TOOL_PEN, we do not report the device as coming from a stylus source.
@@ -10801,7 +10802,7 @@
ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper.getSources());
// However, if the device ever ends up reporting an event with MT_TOOL_PEN, it should be
- // reported with the stylus source, even through the device doesn't support the stylus source.
+ // reported with the stylus source.
processId(mapper, FIRST_TRACKING_ID);
processToolType(mapper, MT_TOOL_PEN);
processPosition(mapper, 100, 200);
@@ -10812,15 +10813,27 @@
WithSource(AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS),
WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS))));
+ // Now that we know the device supports styluses, ensure that the device is re-configured with
+ // the stylus source.
+ ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS, mapper.getSources());
+ {
+ const auto& devices = mReader->getInputDevices();
+ auto deviceInfo =
+ std::find_if(devices.begin(), devices.end(),
+ [](const InputDeviceInfo& info) { return info.getId() == DEVICE_ID; });
+ LOG_ALWAYS_FATAL_IF(deviceInfo == devices.end(), "Cannot find InputDevice");
+ ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS, deviceInfo->getSources());
+ }
+
+ // Ensure the device was not reset to prevent interruptions of any ongoing gestures.
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasNotCalled());
+
processId(mapper, INVALID_TRACKING_ID);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
WithSource(AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS),
WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS))));
-
- // The mapper should still report only a touchscreen source.
- ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper.getSources());
}
// --- MultiTouchInputMapperTest_ExternalDevice ---
diff --git a/services/inputflinger/tests/TestInputListenerMatchers.h b/services/inputflinger/tests/TestInputListenerMatchers.h
index 8721bd8..9db3422 100644
--- a/services/inputflinger/tests/TestInputListenerMatchers.h
+++ b/services/inputflinger/tests/TestInputListenerMatchers.h
@@ -46,7 +46,8 @@
}
MATCHER_P(WithSource, source, "InputEvent with specified source") {
- *result_listener << "expected source " << source << ", but got " << arg.source;
+ *result_listener << "expected source " << inputEventSourceToString(source) << ", but got "
+ << inputEventSourceToString(arg.source);
return arg.source == source;
}
diff --git a/services/sensorservice/AidlSensorHalWrapper.cpp b/services/sensorservice/AidlSensorHalWrapper.cpp
index f67c610..f5b360f 100644
--- a/services/sensorservice/AidlSensorHalWrapper.cpp
+++ b/services/sensorservice/AidlSensorHalWrapper.cpp
@@ -23,6 +23,7 @@
#include <aidlcommonsupport/NativeHandle.h>
#include <android-base/logging.h>
#include <android/binder_manager.h>
+#include <aidl/sensors/convert.h>
using ::aidl::android::hardware::sensors::AdditionalInfo;
using ::aidl::android::hardware::sensors::DynamicSensorInfo;
@@ -34,469 +35,16 @@
using ::android::AidlMessageQueue;
using ::android::hardware::EventFlag;
using ::android::hardware::sensors::V2_1::implementation::MAX_RECEIVE_BUFFER_EVENT_COUNT;
+using ::android::hardware::sensors::implementation::convertToStatus;
+using ::android::hardware::sensors::implementation::convertToSensor;
+using ::android::hardware::sensors::implementation::convertToSensorEvent;
+using ::android::hardware::sensors::implementation::convertFromSensorEvent;
+
namespace android {
namespace {
-status_t convertToStatus(ndk::ScopedAStatus status) {
- if (status.isOk()) {
- return OK;
- } else {
- switch (status.getExceptionCode()) {
- case EX_ILLEGAL_ARGUMENT: {
- return BAD_VALUE;
- }
- case EX_SECURITY: {
- return PERMISSION_DENIED;
- }
- case EX_UNSUPPORTED_OPERATION: {
- return INVALID_OPERATION;
- }
- case EX_SERVICE_SPECIFIC: {
- switch (status.getServiceSpecificError()) {
- case ISensors::ERROR_BAD_VALUE: {
- return BAD_VALUE;
- }
- case ISensors::ERROR_NO_MEMORY: {
- return NO_MEMORY;
- }
- default: {
- return UNKNOWN_ERROR;
- }
- }
- }
- default: {
- return UNKNOWN_ERROR;
- }
- }
- }
-}
-
-void convertToSensor(const SensorInfo &src, sensor_t *dst) {
- dst->name = strdup(src.name.c_str());
- dst->vendor = strdup(src.vendor.c_str());
- dst->version = src.version;
- dst->handle = src.sensorHandle;
- dst->type = (int)src.type;
- dst->maxRange = src.maxRange;
- dst->resolution = src.resolution;
- dst->power = src.power;
- dst->minDelay = src.minDelayUs;
- dst->fifoReservedEventCount = src.fifoReservedEventCount;
- dst->fifoMaxEventCount = src.fifoMaxEventCount;
- dst->stringType = strdup(src.typeAsString.c_str());
- dst->requiredPermission = strdup(src.requiredPermission.c_str());
- dst->maxDelay = src.maxDelayUs;
- dst->flags = src.flags;
- dst->reserved[0] = dst->reserved[1] = 0;
-}
-
-void convertToSensorEvent(const Event &src, sensors_event_t *dst) {
- *dst = {.version = sizeof(sensors_event_t),
- .sensor = src.sensorHandle,
- .type = (int32_t)src.sensorType,
- .reserved0 = 0,
- .timestamp = src.timestamp};
-
- switch (src.sensorType) {
- case SensorType::META_DATA: {
- // Legacy HALs expect the handle reference in the meta data field.
- // Copy it over from the handle of the event.
- dst->meta_data.what = (int32_t)src.payload.get<Event::EventPayload::meta>().what;
- dst->meta_data.sensor = src.sensorHandle;
- // Set the sensor handle to 0 to maintain compatibility.
- dst->sensor = 0;
- break;
- }
-
- case SensorType::ACCELEROMETER:
- case SensorType::MAGNETIC_FIELD:
- case SensorType::ORIENTATION:
- case SensorType::GYROSCOPE:
- case SensorType::GRAVITY:
- case SensorType::LINEAR_ACCELERATION: {
- dst->acceleration.x = src.payload.get<Event::EventPayload::vec3>().x;
- dst->acceleration.y = src.payload.get<Event::EventPayload::vec3>().y;
- dst->acceleration.z = src.payload.get<Event::EventPayload::vec3>().z;
- dst->acceleration.status = (int32_t)src.payload.get<Event::EventPayload::vec3>().status;
- break;
- }
-
- case SensorType::GAME_ROTATION_VECTOR: {
- dst->data[0] = src.payload.get<Event::EventPayload::vec4>().x;
- dst->data[1] = src.payload.get<Event::EventPayload::vec4>().y;
- dst->data[2] = src.payload.get<Event::EventPayload::vec4>().z;
- dst->data[3] = src.payload.get<Event::EventPayload::vec4>().w;
- break;
- }
-
- case SensorType::ROTATION_VECTOR:
- case SensorType::GEOMAGNETIC_ROTATION_VECTOR: {
- dst->data[0] = src.payload.get<Event::EventPayload::data>().values[0];
- dst->data[1] = src.payload.get<Event::EventPayload::data>().values[1];
- dst->data[2] = src.payload.get<Event::EventPayload::data>().values[2];
- dst->data[3] = src.payload.get<Event::EventPayload::data>().values[3];
- dst->data[4] = src.payload.get<Event::EventPayload::data>().values[4];
- break;
- }
-
- case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
- case SensorType::GYROSCOPE_UNCALIBRATED:
- case SensorType::ACCELEROMETER_UNCALIBRATED: {
- dst->uncalibrated_gyro.x_uncalib = src.payload.get<Event::EventPayload::uncal>().x;
- dst->uncalibrated_gyro.y_uncalib = src.payload.get<Event::EventPayload::uncal>().y;
- dst->uncalibrated_gyro.z_uncalib = src.payload.get<Event::EventPayload::uncal>().z;
- dst->uncalibrated_gyro.x_bias = src.payload.get<Event::EventPayload::uncal>().xBias;
- dst->uncalibrated_gyro.y_bias = src.payload.get<Event::EventPayload::uncal>().yBias;
- dst->uncalibrated_gyro.z_bias = src.payload.get<Event::EventPayload::uncal>().zBias;
- break;
- }
-
- case SensorType::HINGE_ANGLE:
- case SensorType::DEVICE_ORIENTATION:
- case SensorType::LIGHT:
- case SensorType::PRESSURE:
- case SensorType::PROXIMITY:
- case SensorType::RELATIVE_HUMIDITY:
- case SensorType::AMBIENT_TEMPERATURE:
- case SensorType::SIGNIFICANT_MOTION:
- case SensorType::STEP_DETECTOR:
- case SensorType::TILT_DETECTOR:
- case SensorType::WAKE_GESTURE:
- case SensorType::GLANCE_GESTURE:
- case SensorType::PICK_UP_GESTURE:
- case SensorType::WRIST_TILT_GESTURE:
- case SensorType::STATIONARY_DETECT:
- case SensorType::MOTION_DETECT:
- case SensorType::HEART_BEAT:
- case SensorType::LOW_LATENCY_OFFBODY_DETECT: {
- dst->data[0] = src.payload.get<Event::EventPayload::scalar>();
- break;
- }
-
- case SensorType::STEP_COUNTER: {
- dst->u64.step_counter = src.payload.get<Event::EventPayload::stepCount>();
- break;
- }
-
- case SensorType::HEART_RATE: {
- dst->heart_rate.bpm = src.payload.get<Event::EventPayload::heartRate>().bpm;
- dst->heart_rate.status =
- (int8_t)src.payload.get<Event::EventPayload::heartRate>().status;
- break;
- }
-
- case SensorType::POSE_6DOF: { // 15 floats
- for (size_t i = 0; i < 15; ++i) {
- dst->data[i] = src.payload.get<Event::EventPayload::pose6DOF>().values[i];
- }
- break;
- }
-
- case SensorType::DYNAMIC_SENSOR_META: {
- dst->dynamic_sensor_meta.connected =
- src.payload.get<Event::EventPayload::dynamic>().connected;
- dst->dynamic_sensor_meta.handle =
- src.payload.get<Event::EventPayload::dynamic>().sensorHandle;
- dst->dynamic_sensor_meta.sensor = NULL; // to be filled in later
-
- memcpy(dst->dynamic_sensor_meta.uuid,
- src.payload.get<Event::EventPayload::dynamic>().uuid.values.data(), 16);
-
- break;
- }
-
- case SensorType::ADDITIONAL_INFO: {
- const AdditionalInfo &srcInfo = src.payload.get<Event::EventPayload::additional>();
-
- additional_info_event_t *dstInfo = &dst->additional_info;
- dstInfo->type = (int32_t)srcInfo.type;
- dstInfo->serial = srcInfo.serial;
-
- switch (srcInfo.payload.getTag()) {
- case AdditionalInfo::AdditionalInfoPayload::Tag::dataInt32: {
- const auto &values =
- srcInfo.payload.get<AdditionalInfo::AdditionalInfoPayload::dataInt32>()
- .values;
- CHECK_EQ(values.size() * sizeof(int32_t), sizeof(dstInfo->data_int32));
- memcpy(dstInfo->data_int32, values.data(), sizeof(dstInfo->data_int32));
- break;
- }
- case AdditionalInfo::AdditionalInfoPayload::Tag::dataFloat: {
- const auto &values =
- srcInfo.payload.get<AdditionalInfo::AdditionalInfoPayload::dataFloat>()
- .values;
- CHECK_EQ(values.size() * sizeof(float), sizeof(dstInfo->data_float));
- memcpy(dstInfo->data_float, values.data(), sizeof(dstInfo->data_float));
- break;
- }
- default: {
- ALOGE("Invalid sensor additional info tag: %d", (int)srcInfo.payload.getTag());
- }
- }
- break;
- }
-
- case SensorType::HEAD_TRACKER: {
- const auto &ht = src.payload.get<Event::EventPayload::headTracker>();
- dst->head_tracker.rx = ht.rx;
- dst->head_tracker.ry = ht.ry;
- dst->head_tracker.rz = ht.rz;
- dst->head_tracker.vx = ht.vx;
- dst->head_tracker.vy = ht.vy;
- dst->head_tracker.vz = ht.vz;
- dst->head_tracker.discontinuity_count = ht.discontinuityCount;
- break;
- }
-
- case SensorType::ACCELEROMETER_LIMITED_AXES:
- case SensorType::GYROSCOPE_LIMITED_AXES:
- dst->limited_axes_imu.x = src.payload.get<Event::EventPayload::limitedAxesImu>().x;
- dst->limited_axes_imu.y = src.payload.get<Event::EventPayload::limitedAxesImu>().y;
- dst->limited_axes_imu.z = src.payload.get<Event::EventPayload::limitedAxesImu>().z;
- dst->limited_axes_imu.x_supported =
- src.payload.get<Event::EventPayload::limitedAxesImu>().xSupported;
- dst->limited_axes_imu.y_supported =
- src.payload.get<Event::EventPayload::limitedAxesImu>().ySupported;
- dst->limited_axes_imu.z_supported =
- src.payload.get<Event::EventPayload::limitedAxesImu>().zSupported;
- break;
-
- case SensorType::ACCELEROMETER_LIMITED_AXES_UNCALIBRATED:
- case SensorType::GYROSCOPE_LIMITED_AXES_UNCALIBRATED:
- dst->limited_axes_imu_uncalibrated.x_uncalib =
- src.payload.get<Event::EventPayload::limitedAxesImuUncal>().x;
- dst->limited_axes_imu_uncalibrated.y_uncalib =
- src.payload.get<Event::EventPayload::limitedAxesImuUncal>().y;
- dst->limited_axes_imu_uncalibrated.z_uncalib =
- src.payload.get<Event::EventPayload::limitedAxesImuUncal>().z;
- dst->limited_axes_imu_uncalibrated.x_bias =
- src.payload.get<Event::EventPayload::limitedAxesImuUncal>().xBias;
- dst->limited_axes_imu_uncalibrated.y_bias =
- src.payload.get<Event::EventPayload::limitedAxesImuUncal>().yBias;
- dst->limited_axes_imu_uncalibrated.z_bias =
- src.payload.get<Event::EventPayload::limitedAxesImuUncal>().zBias;
- dst->limited_axes_imu_uncalibrated.x_supported =
- src.payload.get<Event::EventPayload::limitedAxesImuUncal>().xSupported;
- dst->limited_axes_imu_uncalibrated.y_supported =
- src.payload.get<Event::EventPayload::limitedAxesImuUncal>().ySupported;
- dst->limited_axes_imu_uncalibrated.z_supported =
- src.payload.get<Event::EventPayload::limitedAxesImuUncal>().zSupported;
- break;
-
- case SensorType::HEADING:
- dst->heading.heading = src.payload.get<Event::EventPayload::heading>().heading;
- dst->heading.accuracy = src.payload.get<Event::EventPayload::heading>().accuracy;
- break;
-
- default: {
- CHECK_GE((int32_t)src.sensorType, (int32_t)SensorType::DEVICE_PRIVATE_BASE);
-
- memcpy(dst->data, src.payload.get<Event::EventPayload::data>().values.data(),
- 16 * sizeof(float));
- break;
- }
- }
-}
-
-void convertFromSensorEvent(const sensors_event_t &src, Event *dst) {
- *dst = {
- .timestamp = src.timestamp,
- .sensorHandle = src.sensor,
- .sensorType = (SensorType)src.type,
- };
-
- switch (dst->sensorType) {
- case SensorType::META_DATA: {
- Event::EventPayload::MetaData meta;
- meta.what = (Event::EventPayload::MetaData::MetaDataEventType)src.meta_data.what;
- // Legacy HALs contain the handle reference in the meta data field.
- // Copy that over to the handle of the event. In legacy HALs this
- // field was expected to be 0.
- dst->sensorHandle = src.meta_data.sensor;
- dst->payload.set<Event::EventPayload::Tag::meta>(meta);
- break;
- }
-
- case SensorType::ACCELEROMETER:
- case SensorType::MAGNETIC_FIELD:
- case SensorType::ORIENTATION:
- case SensorType::GYROSCOPE:
- case SensorType::GRAVITY:
- case SensorType::LINEAR_ACCELERATION: {
- Event::EventPayload::Vec3 vec3;
- vec3.x = src.acceleration.x;
- vec3.y = src.acceleration.y;
- vec3.z = src.acceleration.z;
- vec3.status = (SensorStatus)src.acceleration.status;
- dst->payload.set<Event::EventPayload::Tag::vec3>(vec3);
- break;
- }
-
- case SensorType::GAME_ROTATION_VECTOR: {
- Event::EventPayload::Vec4 vec4;
- vec4.x = src.data[0];
- vec4.y = src.data[1];
- vec4.z = src.data[2];
- vec4.w = src.data[3];
- dst->payload.set<Event::EventPayload::Tag::vec4>(vec4);
- break;
- }
-
- case SensorType::ROTATION_VECTOR:
- case SensorType::GEOMAGNETIC_ROTATION_VECTOR: {
- Event::EventPayload::Data data;
- memcpy(data.values.data(), src.data, 5 * sizeof(float));
- dst->payload.set<Event::EventPayload::Tag::data>(data);
- break;
- }
-
- case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
- case SensorType::GYROSCOPE_UNCALIBRATED:
- case SensorType::ACCELEROMETER_UNCALIBRATED: {
- Event::EventPayload::Uncal uncal;
- uncal.x = src.uncalibrated_gyro.x_uncalib;
- uncal.y = src.uncalibrated_gyro.y_uncalib;
- uncal.z = src.uncalibrated_gyro.z_uncalib;
- uncal.xBias = src.uncalibrated_gyro.x_bias;
- uncal.yBias = src.uncalibrated_gyro.y_bias;
- uncal.zBias = src.uncalibrated_gyro.z_bias;
- dst->payload.set<Event::EventPayload::Tag::uncal>(uncal);
- break;
- }
-
- case SensorType::DEVICE_ORIENTATION:
- case SensorType::LIGHT:
- case SensorType::PRESSURE:
- case SensorType::PROXIMITY:
- case SensorType::RELATIVE_HUMIDITY:
- case SensorType::AMBIENT_TEMPERATURE:
- case SensorType::SIGNIFICANT_MOTION:
- case SensorType::STEP_DETECTOR:
- case SensorType::TILT_DETECTOR:
- case SensorType::WAKE_GESTURE:
- case SensorType::GLANCE_GESTURE:
- case SensorType::PICK_UP_GESTURE:
- case SensorType::WRIST_TILT_GESTURE:
- case SensorType::STATIONARY_DETECT:
- case SensorType::MOTION_DETECT:
- case SensorType::HEART_BEAT:
- case SensorType::LOW_LATENCY_OFFBODY_DETECT:
- case SensorType::HINGE_ANGLE: {
- dst->payload.set<Event::EventPayload::Tag::scalar>((float)src.data[0]);
- break;
- }
-
- case SensorType::STEP_COUNTER: {
- dst->payload.set<Event::EventPayload::Tag::stepCount>(src.u64.step_counter);
- break;
- }
-
- case SensorType::HEART_RATE: {
- Event::EventPayload::HeartRate heartRate;
- heartRate.bpm = src.heart_rate.bpm;
- heartRate.status = (SensorStatus)src.heart_rate.status;
- dst->payload.set<Event::EventPayload::Tag::heartRate>(heartRate);
- break;
- }
-
- case SensorType::POSE_6DOF: { // 15 floats
- Event::EventPayload::Pose6Dof pose6DOF;
- for (size_t i = 0; i < 15; ++i) {
- pose6DOF.values[i] = src.data[i];
- }
- dst->payload.set<Event::EventPayload::Tag::pose6DOF>(pose6DOF);
- break;
- }
-
- case SensorType::DYNAMIC_SENSOR_META: {
- DynamicSensorInfo dynamic;
- dynamic.connected = src.dynamic_sensor_meta.connected;
- dynamic.sensorHandle = src.dynamic_sensor_meta.handle;
-
- memcpy(dynamic.uuid.values.data(), src.dynamic_sensor_meta.uuid, 16);
- dst->payload.set<Event::EventPayload::Tag::dynamic>(dynamic);
- break;
- }
-
- case SensorType::ADDITIONAL_INFO: {
- AdditionalInfo info;
- const additional_info_event_t &srcInfo = src.additional_info;
- info.type = (AdditionalInfo::AdditionalInfoType)srcInfo.type;
- info.serial = srcInfo.serial;
-
- AdditionalInfo::AdditionalInfoPayload::Int32Values data;
- CHECK_EQ(data.values.size() * sizeof(int32_t), sizeof(srcInfo.data_int32));
- memcpy(data.values.data(), srcInfo.data_int32, sizeof(srcInfo.data_int32));
- info.payload.set<AdditionalInfo::AdditionalInfoPayload::Tag::dataInt32>(data);
-
- dst->payload.set<Event::EventPayload::Tag::additional>(info);
- break;
- }
-
- case SensorType::HEAD_TRACKER: {
- Event::EventPayload::HeadTracker headTracker;
- headTracker.rx = src.head_tracker.rx;
- headTracker.ry = src.head_tracker.ry;
- headTracker.rz = src.head_tracker.rz;
- headTracker.vx = src.head_tracker.vx;
- headTracker.vy = src.head_tracker.vy;
- headTracker.vz = src.head_tracker.vz;
- headTracker.discontinuityCount = src.head_tracker.discontinuity_count;
-
- dst->payload.set<Event::EventPayload::Tag::headTracker>(headTracker);
- break;
- }
-
- case SensorType::ACCELEROMETER_LIMITED_AXES:
- case SensorType::GYROSCOPE_LIMITED_AXES: {
- Event::EventPayload::LimitedAxesImu limitedAxesImu;
- limitedAxesImu.x = src.limited_axes_imu.x;
- limitedAxesImu.y = src.limited_axes_imu.y;
- limitedAxesImu.z = src.limited_axes_imu.z;
- limitedAxesImu.xSupported = src.limited_axes_imu.x_supported;
- limitedAxesImu.ySupported = src.limited_axes_imu.y_supported;
- limitedAxesImu.zSupported = src.limited_axes_imu.z_supported;
- dst->payload.set<Event::EventPayload::Tag::limitedAxesImu>(limitedAxesImu);
- break;
- }
-
- case SensorType::ACCELEROMETER_LIMITED_AXES_UNCALIBRATED:
- case SensorType::GYROSCOPE_LIMITED_AXES_UNCALIBRATED: {
- Event::EventPayload::LimitedAxesImuUncal limitedAxesImuUncal;
- limitedAxesImuUncal.x = src.limited_axes_imu_uncalibrated.x_uncalib;
- limitedAxesImuUncal.y = src.limited_axes_imu_uncalibrated.y_uncalib;
- limitedAxesImuUncal.z = src.limited_axes_imu_uncalibrated.z_uncalib;
- limitedAxesImuUncal.xBias = src.limited_axes_imu_uncalibrated.x_bias;
- limitedAxesImuUncal.yBias = src.limited_axes_imu_uncalibrated.y_bias;
- limitedAxesImuUncal.zBias = src.limited_axes_imu_uncalibrated.z_bias;
- limitedAxesImuUncal.xSupported = src.limited_axes_imu_uncalibrated.x_supported;
- limitedAxesImuUncal.ySupported = src.limited_axes_imu_uncalibrated.y_supported;
- limitedAxesImuUncal.zSupported = src.limited_axes_imu_uncalibrated.z_supported;
- dst->payload.set<Event::EventPayload::Tag::limitedAxesImuUncal>(limitedAxesImuUncal);
- break;
- }
-
- case SensorType::HEADING: {
- Event::EventPayload::Heading heading;
- heading.heading = src.heading.heading;
- heading.accuracy = src.heading.accuracy;
- dst->payload.set<Event::EventPayload::heading>(heading);
- break;
- }
-
- default: {
- CHECK_GE((int32_t)dst->sensorType, (int32_t)SensorType::DEVICE_PRIVATE_BASE);
-
- Event::EventPayload::Data data;
- memcpy(data.values.data(), src.data, 16 * sizeof(float));
- dst->payload.set<Event::EventPayload::Tag::data>(data);
- break;
- }
- }
-}
-
void serviceDied(void *cookie) {
ALOGW("Sensors HAL died, attempting to reconnect.");
((AidlSensorHalWrapper *)cookie)->prepareForReconnect();
diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp
index 5ad4815..0eeb820 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -75,6 +75,7 @@
static_libs: [
"libaidlcommonsupport",
"android.hardware.sensors@1.0-convert",
+ "android.hardware.sensors-V1-convert",
"android.hardware.sensors-V1-ndk",
],
diff --git a/services/sensorservice/aidl/Android.bp b/services/sensorservice/aidl/Android.bp
new file mode 100644
index 0000000..bbf49da
--- /dev/null
+++ b/services/sensorservice/aidl/Android.bp
@@ -0,0 +1,43 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_library_shared {
+ name: "libsensorserviceaidl",
+ srcs: [
+ "EventQueue.cpp",
+ "DirectReportChannel.cpp",
+ "SensorManager.cpp",
+ "utils.cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ header_libs: ["jni_headers"],
+ shared_libs: [
+ "libbase",
+ "libutils",
+ "libcutils",
+ "libbinder_ndk",
+ "libsensor",
+ "android.frameworks.sensorservice-V1-ndk",
+ "android.hardware.sensors-V1-ndk",
+ ],
+ export_include_dirs: [
+ "include/",
+ ],
+ static_libs: [
+ "android.hardware.sensors-V1-convert",
+ ],
+
+ export_header_lib_headers: ["jni_headers"],
+ local_include_dirs: [
+ "include/sensorserviceaidl/",
+ ],
+}
diff --git a/services/sensorservice/aidl/DirectReportChannel.cpp b/services/sensorservice/aidl/DirectReportChannel.cpp
new file mode 100644
index 0000000..cab53c1
--- /dev/null
+++ b/services/sensorservice/aidl/DirectReportChannel.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DirectReportChannel.h"
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+DirectReportChannel::DirectReportChannel(::android::SensorManager& manager, int channelId)
+ : mManager(manager), mId(channelId) {}
+
+DirectReportChannel::~DirectReportChannel() {
+ mManager.destroyDirectChannel(mId);
+}
+
+ndk::ScopedAStatus DirectReportChannel::configure(
+ int32_t sensorHandle, ::aidl::android::hardware::sensors::ISensors::RateLevel rate,
+ int32_t* _aidl_return) {
+ int token = mManager.configureDirectChannel(mId, sensorHandle, static_cast<int>(rate));
+ if (token <= 0) {
+ return ndk::ScopedAStatus::fromServiceSpecificError(token);
+ }
+ *_aidl_return = token;
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/sensorservice/aidl/DirectReportChannel.h b/services/sensorservice/aidl/DirectReportChannel.h
new file mode 100644
index 0000000..d9ea73d
--- /dev/null
+++ b/services/sensorservice/aidl/DirectReportChannel.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <aidl/android/frameworks/sensorservice/BnDirectReportChannel.h>
+#include <aidl/android/hardware/sensors/ISensors.h>
+#include <sensor/SensorManager.h>
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+class DirectReportChannel final
+ : public ::aidl::android::frameworks::sensorservice::BnDirectReportChannel {
+public:
+ DirectReportChannel(::android::SensorManager& manager, int channelId);
+ ~DirectReportChannel();
+
+ ndk::ScopedAStatus configure(int32_t sensorHandle,
+ ::aidl::android::hardware::sensors::ISensors::RateLevel rate,
+ int32_t* _aidl_return) override;
+
+private:
+ ::android::SensorManager& mManager;
+ const int mId;
+};
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/sensorservice/aidl/EventQueue.cpp b/services/sensorservice/aidl/EventQueue.cpp
new file mode 100644
index 0000000..d4e8906
--- /dev/null
+++ b/services/sensorservice/aidl/EventQueue.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "EventQueue.h"
+#include "utils.h"
+
+#include <android-base/logging.h>
+#include <utils/Looper.h>
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+using ::aidl::android::frameworks::sensorservice::IEventQueueCallback;
+using ::aidl::android::hardware::sensors::Event;
+
+class EventQueueLooperCallback : public ::android::LooperCallback {
+public:
+ EventQueueLooperCallback(sp<::android::SensorEventQueue> queue,
+ std::shared_ptr<IEventQueueCallback> callback)
+ : mQueue(queue), mCallback(callback) {}
+
+ int handleEvent(__unused int fd, __unused int events, __unused void* data) {
+ ASensorEvent event;
+ ssize_t actual;
+
+ auto internalQueue = mQueue.promote();
+ if (internalQueue == nullptr) {
+ return 1;
+ }
+
+ while ((actual = internalQueue->read(&event, 1)) > 0) {
+ internalQueue->sendAck(&event, actual);
+ ndk::ScopedAStatus ret = mCallback->onEvent(convertEvent(event));
+ if (!ret.isOk()) {
+ LOG(ERROR) << "Failed to envoke EventQueueCallback: " << ret;
+ }
+ }
+
+ return 1; // continue to receive callbacks
+ }
+
+private:
+ wp<::android::SensorEventQueue> mQueue;
+ std::shared_ptr<IEventQueueCallback> mCallback;
+};
+
+EventQueue::EventQueue(std::shared_ptr<IEventQueueCallback> callback, sp<::android::Looper> looper,
+ sp<::android::SensorEventQueue> internalQueue)
+ : mLooper(looper), mInternalQueue(internalQueue) {
+ mLooper->addFd(internalQueue->getFd(), ALOOPER_POLL_CALLBACK, ALOOPER_EVENT_INPUT,
+ new EventQueueLooperCallback(internalQueue, callback), nullptr);
+}
+
+// FIXME why was this on onLastStrongRef instead of dtor?
+EventQueue::~EventQueue() {
+ mLooper->removeFd(mInternalQueue->getFd());
+}
+
+ndk::ScopedAStatus EventQueue::enableSensor(int32_t in_sensorHandle, int32_t in_samplingPeriodUs,
+ int64_t in_maxBatchReportLatencyUs) {
+ return convertResult(mInternalQueue->enableSensor(in_sensorHandle, in_samplingPeriodUs,
+ in_maxBatchReportLatencyUs, 0));
+}
+
+ndk::ScopedAStatus EventQueue::disableSensor(int32_t in_sensorHandle) {
+ return convertResult(mInternalQueue->disableSensor(in_sensorHandle));
+}
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/sensorservice/aidl/EventQueue.h b/services/sensorservice/aidl/EventQueue.h
new file mode 100644
index 0000000..0ae1eba
--- /dev/null
+++ b/services/sensorservice/aidl/EventQueue.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "SensorManagerAidl.h"
+
+#include <aidl/android/frameworks/sensorservice/BnEventQueue.h>
+#include <sensor/SensorManager.h>
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+struct EventQueue final : public aidl::android::frameworks::sensorservice::BnEventQueue {
+ EventQueue(
+ std::shared_ptr<aidl::android::frameworks::sensorservice::IEventQueueCallback> callback,
+ sp<::android::Looper> looper, sp<::android::SensorEventQueue> internalQueue);
+ ~EventQueue();
+
+ ndk::ScopedAStatus enableSensor(int32_t in_sensorHandle, int32_t in_samplingPeriodUs,
+ int64_t in_maxBatchReportLatencyUs) override;
+ ndk::ScopedAStatus disableSensor(int32_t sensorHandle) override;
+
+private:
+ friend class EventQueueLooperCallback;
+ sp<::android::Looper> mLooper;
+ sp<::android::SensorEventQueue> mInternalQueue;
+};
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/sensorservice/aidl/SensorManager.cpp b/services/sensorservice/aidl/SensorManager.cpp
new file mode 100644
index 0000000..6d8d574
--- /dev/null
+++ b/services/sensorservice/aidl/SensorManager.cpp
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// LOG_TAG defined via build flag.
+#ifndef LOG_TAG
+#define LOG_TAG "AidlSensorManager"
+#endif
+
+#include "DirectReportChannel.h"
+#include "EventQueue.h"
+#include "SensorManagerAidl.h"
+#include "utils.h"
+
+#include <aidl/android/hardware/sensors/ISensors.h>
+#include <android-base/logging.h>
+#include <android/binder_ibinder.h>
+#include <sched.h>
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+using ::aidl::android::frameworks::sensorservice::IDirectReportChannel;
+using ::aidl::android::frameworks::sensorservice::IEventQueue;
+using ::aidl::android::frameworks::sensorservice::IEventQueueCallback;
+using ::aidl::android::frameworks::sensorservice::ISensorManager;
+using ::aidl::android::hardware::common::Ashmem;
+using ::aidl::android::hardware::sensors::ISensors;
+using ::aidl::android::hardware::sensors::SensorInfo;
+using ::aidl::android::hardware::sensors::SensorType;
+using ::android::frameworks::sensorservice::implementation::SensorManagerAidl;
+
+static const char* POLL_THREAD_NAME = "aidl_ssvc_poll";
+
+SensorManagerAidl::SensorManagerAidl(JavaVM* vm)
+ : mLooper(new Looper(false)), mStopThread(true), mJavaVm(vm) {}
+SensorManagerAidl::~SensorManagerAidl() {
+ // Stops pollAll inside the thread.
+ std::lock_guard<std::mutex> lock(mThreadMutex);
+
+ mStopThread = true;
+ if (mLooper != nullptr) {
+ mLooper->wake();
+ }
+ if (mPollThread.joinable()) {
+ mPollThread.join();
+ }
+}
+
+ndk::ScopedAStatus createDirectChannel(::android::SensorManager& manager, size_t size, int type,
+ const native_handle_t* handle,
+ std::shared_ptr<IDirectReportChannel>* chan) {
+ int channelId = manager.createDirectChannel(size, type, handle);
+ if (channelId < 0) {
+ return convertResult(channelId);
+ }
+ if (channelId == 0) {
+ return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_UNKNOWN_ERROR);
+ }
+ *chan = ndk::SharedRefBase::make<DirectReportChannel>(manager, channelId);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus SensorManagerAidl::createAshmemDirectChannel(
+ const Ashmem& in_mem, int64_t in_size,
+ std::shared_ptr<IDirectReportChannel>* _aidl_return) {
+ if (in_size > in_mem.size || in_size < ISensors::DIRECT_REPORT_SENSOR_EVENT_TOTAL_LENGTH) {
+ return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_BAD_VALUE);
+ }
+ native_handle_t* handle = native_handle_create(1, 0);
+ handle->data[0] = dup(in_mem.fd.get());
+
+ auto status = createDirectChannel(getInternalManager(), in_size, SENSOR_DIRECT_MEM_TYPE_ASHMEM,
+ handle, _aidl_return);
+ int result = native_handle_close(handle);
+ CHECK(result == 0) << "Failed to close the native_handle_t: " << result;
+ result = native_handle_delete(handle);
+ CHECK(result == 0) << "Failed to delete the native_handle_t: " << result;
+
+ return status;
+}
+
+ndk::ScopedAStatus SensorManagerAidl::createGrallocDirectChannel(
+ const ndk::ScopedFileDescriptor& in_mem, int64_t in_size,
+ std::shared_ptr<IDirectReportChannel>* _aidl_return) {
+ native_handle_t* handle = native_handle_create(1, 0);
+ handle->data[0] = dup(in_mem.get());
+
+ auto status = createDirectChannel(getInternalManager(), in_size, SENSOR_DIRECT_MEM_TYPE_GRALLOC,
+ handle, _aidl_return);
+ int result = native_handle_close(handle);
+ CHECK(result == 0) << "Failed to close the native_handle_t: " << result;
+ result = native_handle_delete(handle);
+ CHECK(result == 0) << "Failed to delete the native_handle_t: " << result;
+
+ return status;
+}
+
+ndk::ScopedAStatus SensorManagerAidl::createEventQueue(
+ const std::shared_ptr<IEventQueueCallback>& in_callback,
+ std::shared_ptr<IEventQueue>* _aidl_return) {
+ if (in_callback == nullptr) {
+ return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_BAD_VALUE);
+ }
+
+ sp<::android::Looper> looper = getLooper();
+ if (looper == nullptr) {
+ LOG(ERROR) << "::android::SensorManagerAidl::createEventQueue cannot initialize looper";
+ return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_UNKNOWN_ERROR);
+ }
+
+ String8 package(String8::format("aidl_client_pid_%d", AIBinder_getCallingPid()));
+ sp<::android::SensorEventQueue> internalQueue = getInternalManager().createEventQueue(package);
+ if (internalQueue == nullptr) {
+ LOG(ERROR) << "::android::SensorManagerAidl::createEventQueue returns nullptr.";
+ return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_UNKNOWN_ERROR);
+ }
+
+ *_aidl_return = ndk::SharedRefBase::make<EventQueue>(in_callback, looper, internalQueue);
+
+ return ndk::ScopedAStatus::ok();
+}
+
+SensorInfo convertSensor(Sensor src) {
+ SensorInfo dst;
+ dst.sensorHandle = src.getHandle();
+ dst.name = src.getName();
+ dst.vendor = src.getVendor();
+ dst.version = src.getVersion();
+ dst.type = static_cast<SensorType>(src.getType());
+ dst.typeAsString = src.getStringType();
+ // maxRange uses maxValue because ::android::Sensor wraps the
+ // internal sensor_t in this way.
+ dst.maxRange = src.getMaxValue();
+ dst.resolution = src.getResolution();
+ dst.power = src.getPowerUsage();
+ dst.minDelayUs = src.getMinDelay();
+ dst.fifoReservedEventCount = src.getFifoReservedEventCount();
+ dst.fifoMaxEventCount = src.getFifoMaxEventCount();
+ dst.requiredPermission = src.getRequiredPermission();
+ dst.maxDelayUs = src.getMaxDelay();
+ dst.flags = src.getFlags();
+ return dst;
+}
+
+ndk::ScopedAStatus SensorManagerAidl::getDefaultSensor(SensorType in_type,
+ SensorInfo* _aidl_return) {
+ ::android::Sensor const* sensor =
+ getInternalManager().getDefaultSensor(static_cast<int>(in_type));
+ if (!sensor) {
+ return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_NOT_EXIST);
+ }
+ *_aidl_return = convertSensor(*sensor);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus SensorManagerAidl::getSensorList(std::vector<SensorInfo>* _aidl_return) {
+ Sensor const* const* list;
+ _aidl_return->clear();
+ ssize_t count = getInternalManager().getSensorList(&list);
+ if (count < 0 || list == nullptr) {
+ LOG(ERROR) << "SensorMAanger::getSensorList failed with count: " << count;
+ return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_UNKNOWN_ERROR);
+ }
+ _aidl_return->reserve(static_cast<size_t>(count));
+ for (ssize_t i = 0; i < count; ++i) {
+ _aidl_return->push_back(convertSensor(*list[i]));
+ }
+
+ return ndk::ScopedAStatus::ok();
+}
+
+::android::SensorManager& SensorManagerAidl::getInternalManager() {
+ std::lock_guard<std::mutex> lock(mInternalManagerMutex);
+ if (mInternalManager == nullptr) {
+ mInternalManager = &::android::SensorManager::getInstanceForPackage(
+ String16(ISensorManager::descriptor));
+ }
+ return *mInternalManager;
+}
+
+/* One global looper for all event queues created from this SensorManager. */
+sp<Looper> SensorManagerAidl::getLooper() {
+ std::lock_guard<std::mutex> lock(mThreadMutex);
+
+ if (!mPollThread.joinable()) {
+ // if thread not initialized, start thread
+ mStopThread = false;
+ std::thread pollThread{[&stopThread = mStopThread, looper = mLooper, javaVm = mJavaVm] {
+ struct sched_param p = {0};
+ p.sched_priority = 10;
+ if (sched_setscheduler(0 /* current thread*/, SCHED_FIFO, &p) != 0) {
+ LOG(ERROR) << "Could not use SCHED_FIFO for looper thread: " << strerror(errno);
+ }
+
+ // set looper
+ Looper::setForThread(looper);
+
+ // Attach the thread to JavaVM so that pollAll do not crash if the thread
+ // eventually calls into Java.
+ JavaVMAttachArgs args{.version = JNI_VERSION_1_2,
+ .name = POLL_THREAD_NAME,
+ .group = nullptr};
+ JNIEnv* env;
+ if (javaVm->AttachCurrentThread(&env, &args) != JNI_OK) {
+ LOG(FATAL) << "Cannot attach SensorManager looper thread to Java VM.";
+ }
+
+ LOG(INFO) << POLL_THREAD_NAME << " started.";
+ for (;;) {
+ int pollResult = looper->pollAll(-1 /* timeout */);
+ if (pollResult == Looper::POLL_WAKE) {
+ if (stopThread == true) {
+ LOG(INFO) << POLL_THREAD_NAME << ": requested to stop";
+ break;
+ } else {
+ LOG(INFO) << POLL_THREAD_NAME << ": spurious wake up, back to work";
+ }
+ } else {
+ LOG(ERROR) << POLL_THREAD_NAME << ": Looper::pollAll returns unexpected "
+ << pollResult;
+ break;
+ }
+ }
+
+ if (javaVm->DetachCurrentThread() != JNI_OK) {
+ LOG(ERROR) << "Cannot detach SensorManager looper thread from Java VM.";
+ }
+
+ LOG(INFO) << POLL_THREAD_NAME << " is terminated.";
+ }};
+ mPollThread = std::move(pollThread);
+ }
+ return mLooper;
+}
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/sensorservice/aidl/include/sensorserviceaidl/SensorManagerAidl.h b/services/sensorservice/aidl/include/sensorserviceaidl/SensorManagerAidl.h
new file mode 100644
index 0000000..c77ee88
--- /dev/null
+++ b/services/sensorservice/aidl/include/sensorserviceaidl/SensorManagerAidl.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/frameworks/sensorservice/BnSensorManager.h>
+#include <jni.h>
+#include <sensor/SensorManager.h>
+#include <utils/Looper.h>
+#include <mutex>
+#include <thread>
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+class SensorManagerAidl : public ::aidl::android::frameworks::sensorservice::BnSensorManager {
+public:
+ explicit SensorManagerAidl(JavaVM* vm);
+ ~SensorManagerAidl();
+
+ ::ndk::ScopedAStatus createAshmemDirectChannel(
+ const ::aidl::android::hardware::common::Ashmem& in_mem, int64_t in_size,
+ std::shared_ptr<::aidl::android::frameworks::sensorservice::IDirectReportChannel>*
+ _aidl_return) override;
+ ::ndk::ScopedAStatus createEventQueue(
+ const std::shared_ptr<::aidl::android::frameworks::sensorservice::IEventQueueCallback>&
+ in_callback,
+ std::shared_ptr<::aidl::android::frameworks::sensorservice::IEventQueue>* _aidl_return)
+ override;
+ ::ndk::ScopedAStatus createGrallocDirectChannel(
+ const ::ndk::ScopedFileDescriptor& in_buffer, int64_t in_size,
+ std::shared_ptr<::aidl::android::frameworks::sensorservice::IDirectReportChannel>*
+ _aidl_return) override;
+ ::ndk::ScopedAStatus getDefaultSensor(
+ ::aidl::android::hardware::sensors::SensorType in_type,
+ ::aidl::android::hardware::sensors::SensorInfo* _aidl_return) override;
+ ::ndk::ScopedAStatus getSensorList(
+ std::vector<::aidl::android::hardware::sensors::SensorInfo>* _aidl_return) override;
+
+private:
+ // Block until ::android::SensorManager is initialized.
+ ::android::SensorManager& getInternalManager();
+ sp<Looper> getLooper();
+
+ std::mutex mInternalManagerMutex;
+ ::android::SensorManager* mInternalManager = nullptr; // does not own
+ sp<Looper> mLooper;
+
+ volatile bool mStopThread;
+ std::mutex mThreadMutex; // protects mPollThread
+ std::thread mPollThread;
+
+ JavaVM* mJavaVm;
+};
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/sensorservice/aidl/utils.cpp b/services/sensorservice/aidl/utils.cpp
new file mode 100644
index 0000000..26bcdc5
--- /dev/null
+++ b/services/sensorservice/aidl/utils.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "utils.h"
+
+#include <aidl/android/frameworks/sensorservice/ISensorManager.h>
+#include <aidl/sensors/convert.h>
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+ndk::ScopedAStatus convertResult(status_t src) {
+ using ::aidl::android::frameworks::sensorservice::ISensorManager;
+
+ int err = 0;
+ switch (src) {
+ case OK:
+ return ndk::ScopedAStatus::ok();
+ case NAME_NOT_FOUND:
+ err = ISensorManager::RESULT_NOT_EXIST;
+ break;
+ case NO_MEMORY:
+ err = ISensorManager::RESULT_NO_MEMORY;
+ break;
+ case NO_INIT:
+ err = ISensorManager::RESULT_NO_INIT;
+ break;
+ case PERMISSION_DENIED:
+ err = ISensorManager::RESULT_PERMISSION_DENIED;
+ break;
+ case BAD_VALUE:
+ err = ISensorManager::RESULT_BAD_VALUE;
+ break;
+ case INVALID_OPERATION:
+ err = ISensorManager::RESULT_INVALID_OPERATION;
+ break;
+ default:
+ err = ISensorManager::RESULT_UNKNOWN_ERROR;
+ }
+ return ndk::ScopedAStatus::fromServiceSpecificError(err);
+}
+
+::aidl::android::hardware::sensors::Event convertEvent(const ::ASensorEvent& src) {
+ ::aidl::android::hardware::sensors::Event dst;
+ ::android::hardware::sensors::implementation::
+ convertFromSensorEvent(reinterpret_cast<const sensors_event_t&>(src), &dst);
+ return dst;
+}
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/sensorservice/aidl/utils.h b/services/sensorservice/aidl/utils.h
new file mode 100644
index 0000000..06ba59e
--- /dev/null
+++ b/services/sensorservice/aidl/utils.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <aidl/android/hardware/sensors/Event.h>
+#include <sensor/Sensor.h>
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+::ndk::ScopedAStatus convertResult(status_t status);
+::aidl::android::hardware::sensors::Event convertEvent(const ::ASensorEvent& event);
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 9868c8e..a5195f4 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -41,6 +41,7 @@
#include "Display/DisplaySnapshot.h"
#include "DisplayDevice.h"
+#include "FrontEnd/DisplayInfo.h"
#include "Layer.h"
#include "RefreshRateOverlay.h"
#include "SurfaceFlinger.h"
@@ -131,7 +132,7 @@
}
}
-auto DisplayDevice::getInputInfo() const -> InputInfo {
+auto DisplayDevice::getFrontEndInfo() const -> frontend::DisplayInfo {
gui::DisplayInfo info;
info.displayId = getLayerStack().id;
@@ -160,7 +161,9 @@
return {.info = info,
.transform = displayTransform,
.receivesInput = receivesInput(),
- .isSecure = isSecure()};
+ .isSecure = isSecure(),
+ .isPrimary = isPrimary(),
+ .rotationFlags = ui::Transform::toRotationFlags(mOrientation)};
}
void DisplayDevice::setPowerMode(hal::PowerMode mode) {
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 1602a71..4b64aab 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -45,11 +45,11 @@
#include "DisplayHardware/DisplayMode.h"
#include "DisplayHardware/Hal.h"
#include "DisplayHardware/PowerAdvisor.h"
+#include "FrontEnd/DisplayInfo.h"
#include "Scheduler/RefreshRateSelector.h"
#include "ThreadContext.h"
#include "TracedOrdinal.h"
#include "Utils/Dumper.h"
-
namespace android {
class Fence;
@@ -167,14 +167,7 @@
void setDisplayName(const std::string& displayName);
const std::string& getDisplayName() const { return mDisplayName; }
- struct InputInfo {
- gui::DisplayInfo info;
- ui::Transform transform;
- bool receivesInput;
- bool isSecure;
- };
-
- InputInfo getInputInfo() const;
+ surfaceflinger::frontend::DisplayInfo getFrontEndInfo() const;
/* ------------------------------------------------------------------------
* Display power mode management.
diff --git a/services/surfaceflinger/FrontEnd/DisplayInfo.h b/services/surfaceflinger/FrontEnd/DisplayInfo.h
new file mode 100644
index 0000000..0c7b24a
--- /dev/null
+++ b/services/surfaceflinger/FrontEnd/DisplayInfo.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gui/DisplayInfo.h>
+
+namespace android::surfaceflinger::frontend {
+
+// Display information needed to populate input and calculate layer geometry.
+struct DisplayInfo {
+ gui::DisplayInfo info;
+ ui::Transform transform;
+ bool receivesInput;
+ bool isSecure;
+ // TODO(b/238781169) can eliminate once sPrimaryDisplayRotationFlags is removed.
+ bool isPrimary;
+ ui::Transform::RotationFlags rotationFlags;
+};
+
+} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/FrontEnd/TransactionHandler.cpp b/services/surfaceflinger/FrontEnd/TransactionHandler.cpp
index 95961fe..8629671 100644
--- a/services/surfaceflinger/FrontEnd/TransactionHandler.cpp
+++ b/services/surfaceflinger/FrontEnd/TransactionHandler.cpp
@@ -24,7 +24,7 @@
#include "TransactionHandler.h"
-namespace android {
+namespace android::surfaceflinger::frontend {
void TransactionHandler::queueTransaction(TransactionState&& state) {
mLocklessTransactionQueue.push(std::move(state));
@@ -186,4 +186,4 @@
mStalledTransactions.erase(it);
}
}
-} // namespace android
+} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/FrontEnd/TransactionHandler.h b/services/surfaceflinger/FrontEnd/TransactionHandler.h
index 2b6f07d..a06b870 100644
--- a/services/surfaceflinger/FrontEnd/TransactionHandler.h
+++ b/services/surfaceflinger/FrontEnd/TransactionHandler.h
@@ -18,9 +18,6 @@
#include <semaphore.h>
#include <cstdint>
-#include <mutex>
-#include <queue>
-#include <thread>
#include <vector>
#include <LocklessQueue.h>
@@ -30,6 +27,10 @@
#include <ftl/small_vector.h>
namespace android {
+
+class TestableSurfaceFlinger;
+namespace surfaceflinger::frontend {
+
class TransactionHandler {
public:
struct TransactionFlushState {
@@ -60,7 +61,7 @@
private:
// For unit tests
- friend class TestableSurfaceFlinger;
+ friend class ::android::TestableSurfaceFlinger;
int flushPendingTransactionQueues(std::vector<TransactionState>&, TransactionFlushState&);
TransactionReadiness applyFilters(TransactionFlushState&);
@@ -71,5 +72,5 @@
ftl::SmallVector<TransactionFilter, 2> mTransactionReadyFilters;
std::vector<uint64_t> mStalledTransactions;
};
-
+} // namespace surfaceflinger::frontend
} // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 37eb20b..d53f0b1 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -3973,17 +3973,14 @@
}
LayerSnapshotGuard::LayerSnapshotGuard(Layer* layer) : mLayer(layer) {
- LOG_ALWAYS_FATAL_IF(!mLayer, "LayerSnapshotGuard received a null layer.");
- mLayer->mLayerFE->mSnapshot = std::move(mLayer->mSnapshot);
- LOG_ALWAYS_FATAL_IF(!mLayer->mLayerFE->mSnapshot,
- "LayerFE snapshot null after taking ownership from layer");
+ if (mLayer) {
+ mLayer->mLayerFE->mSnapshot = std::move(mLayer->mSnapshot);
+ }
}
LayerSnapshotGuard::~LayerSnapshotGuard() {
if (mLayer) {
mLayer->mSnapshot = std::move(mLayer->mLayerFE->mSnapshot);
- LOG_ALWAYS_FATAL_IF(!mLayer->mSnapshot,
- "Layer snapshot null after taking ownership from LayerFE");
}
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a723a7d..032541c 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -180,6 +180,7 @@
using base::StringAppendF;
using display::PhysicalDisplay;
using display::PhysicalDisplays;
+using frontend::TransactionHandler;
using gui::DisplayInfo;
using gui::GameMode;
using gui::IDisplayEventConnection;
@@ -2190,14 +2191,13 @@
refreshArgs.updatingOutputGeometryThisFrame = mVisibleRegionsDirty;
refreshArgs.updatingGeometryThisFrame = mGeometryDirty.exchange(false) || mVisibleRegionsDirty;
- std::vector<sp<Layer>> layers;
+ std::vector<Layer*> layers;
mDrawingState.traverseInZOrder([&refreshArgs, &layers](Layer* layer) {
- auto strongLayer = sp<Layer>::fromExisting(layer);
if (auto layerFE = layer->getCompositionEngineLayerFE()) {
layer->updateSnapshot(refreshArgs.updatingGeometryThisFrame);
refreshArgs.layers.push_back(layerFE);
- layers.push_back(std::move(strongLayer));
+ layers.push_back(layer);
}
});
refreshArgs.blursAreExpensive = mBlursAreExpensive;
@@ -2229,8 +2229,8 @@
{
std::vector<LayerSnapshotGuard> layerSnapshotGuards;
- for (auto& layer : layers) {
- layerSnapshotGuards.emplace_back(layer.get());
+ for (Layer* layer : layers) {
+ layerSnapshotGuards.emplace_back(layer);
}
mCompositionEngine->present(refreshArgs);
}
@@ -3128,6 +3128,10 @@
const bool displayTransactionNeeded = transactionFlags & eDisplayTransactionNeeded;
if (displayTransactionNeeded) {
processDisplayChangesLocked();
+ mFrontEndDisplayInfos.clear();
+ for (const auto& [_, display] : mDisplays) {
+ mFrontEndDisplayInfos.try_emplace(display->getLayerStack(), display->getFrontEndInfo());
+ }
}
mForceTransactionDisplayChange = displayTransactionNeeded;
@@ -3297,29 +3301,6 @@
void SurfaceFlinger::buildWindowInfos(std::vector<WindowInfo>& outWindowInfos,
std::vector<DisplayInfo>& outDisplayInfos) {
- display::DisplayMap<ui::LayerStack, DisplayDevice::InputInfo> displayInputInfos;
-
- for (const auto& [_, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) {
- const auto layerStack = display->getLayerStack();
- const auto info = display->getInputInfo();
-
- const auto [it, emplaced] = displayInputInfos.try_emplace(layerStack, info);
- if (emplaced) {
- continue;
- }
-
- // If the layer stack is mirrored on multiple displays, the first display that is configured
- // to receive input takes precedence.
- auto& otherInfo = it->second;
- if (otherInfo.receivesInput) {
- ALOGW_IF(display->receivesInput(),
- "Multiple displays claim to accept input for the same layer stack: %u",
- layerStack.id);
- } else {
- otherInfo = info;
- }
- }
-
static size_t sNumWindowInfos = 0;
outWindowInfos.reserve(sNumWindowInfos);
sNumWindowInfos = 0;
@@ -3327,8 +3308,8 @@
mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
if (!layer->needsInputInfo()) return;
- const auto opt = displayInputInfos.get(layer->getLayerStack())
- .transform([](const DisplayDevice::InputInfo& info) {
+ const auto opt = mFrontEndDisplayInfos.get(layer->getLayerStack())
+ .transform([](const frontend::DisplayInfo& info) {
return Layer::InputDisplayArgs{&info.transform, info.isSecure};
});
@@ -3337,8 +3318,8 @@
sNumWindowInfos = outWindowInfos.size();
- outDisplayInfos.reserve(displayInputInfos.size());
- for (const auto& [_, info] : displayInputInfos) {
+ outDisplayInfos.reserve(mFrontEndDisplayInfos.size());
+ for (const auto& [_, info] : mFrontEndDisplayInfos) {
outDisplayInfos.push_back(info.info);
}
}
@@ -3353,12 +3334,7 @@
std::vector<LayerSnapshotGuard> layerSnapshotGuards;
mDrawingState.traverse([&layerSnapshotGuards](Layer* layer) {
- auto strongLayer = sp<Layer>::fromExisting(layer);
- const LayerSnapshot* snapshot = layer->getLayerSnapshot();
- if (!snapshot) {
- LOG_ALWAYS_FATAL("Layer snapshot unexpectedly null");
- }
- if (snapshot->compositionType ==
+ if (layer->getLayerSnapshot()->compositionType ==
aidl::android::hardware::graphics::composer3::Composition::CURSOR) {
layer->updateSnapshot(false /* updateGeometry */);
layerSnapshotGuards.emplace_back(layer);
@@ -6415,8 +6391,10 @@
std::unique_ptr<RenderArea> renderArea = renderAreaFuture.get();
if (!renderArea) {
ALOGW("Skipping screen capture because of invalid render area.");
- captureResults.fenceResult = base::unexpected(NO_MEMORY);
- captureListener->onScreenCaptureCompleted(captureResults);
+ if (captureListener) {
+ captureResults.fenceResult = base::unexpected(NO_MEMORY);
+ captureListener->onScreenCaptureCompleted(captureResults);
+ }
return ftl::yield<FenceResult>(base::unexpected(NO_ERROR)).share();
}
@@ -6502,7 +6480,6 @@
layers.reserve(layerCount);
std::unordered_set<compositionengine::LayerFE*> filterForScreenshot;
traverseLayers([&](Layer* layer) {
- auto strongLayer = sp<Layer>::fromExisting(layer);
captureResults.capturedHdrLayers |= isHdrLayer(layer);
// Layer::prepareClientComposition uses the layer's snapshot to populate the resulting
// LayerSettings. Calling Layer::updateSnapshot ensures that LayerSettings are
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index c2d3343..50e8e73 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -66,6 +66,7 @@
#include "DisplayIdGenerator.h"
#include "Effects/Daltonizer.h"
#include "FlagManager.h"
+#include "FrontEnd/DisplayInfo.h"
#include "FrontEnd/LayerCreationArgs.h"
#include "FrontEnd/TransactionHandler.h"
#include "LayerVector.h"
@@ -120,6 +121,7 @@
class ScreenCapturer;
class WindowInfosListenerInvoker;
+using frontend::TransactionHandler;
using gui::CaptureArgs;
using gui::DisplayCaptureArgs;
using gui::IRegionSamplingListener;
@@ -1366,6 +1368,7 @@
} mPowerHintSessionMode;
TransactionHandler mTransactionHandler;
+ display::DisplayMap<ui::LayerStack, frontend::DisplayInfo> mFrontEndDisplayInfos;
};
class SurfaceComposerAIDL : public gui::BnSurfaceComposer {
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index 488d4a9..d84698f 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -42,6 +42,8 @@
using testing::Return;
using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+using frontend::TransactionHandler;
+
constexpr nsecs_t TRANSACTION_TIMEOUT = s2ns(5);
class TransactionApplicationTest : public testing::Test {
public:
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 4f7b923..475bc40 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -715,6 +715,17 @@
capabilities->minImageExtent = VkExtent2D{1, 1};
capabilities->maxImageExtent = VkExtent2D{4096, 4096};
+ if (capabilities->maxImageExtent.height <
+ capabilities->currentExtent.height) {
+ capabilities->maxImageExtent.height =
+ capabilities->currentExtent.height;
+ }
+
+ if (capabilities->maxImageExtent.width <
+ capabilities->currentExtent.width) {
+ capabilities->maxImageExtent.width = capabilities->currentExtent.width;
+ }
+
capabilities->maxImageArrayLayers = 1;
capabilities->supportedTransforms = kSupportedTransforms;
@@ -743,7 +754,6 @@
const InstanceData& instance_data = GetData(pdev);
- bool wide_color_support = false;
uint64_t consumer_usage = 0;
bool colorspace_ext =
instance_data.hook_extensions.test(ProcHook::EXT_swapchain_colorspace);
@@ -754,27 +764,15 @@
if (!surfaceless_enabled) {
return VK_ERROR_SURFACE_LOST_KHR;
}
- // Support for VK_GOOGLE_surfaceless_query. The EGL loader
- // unconditionally supports wide color formats, even if they will cause
- // a SurfaceFlinger fallback. Based on that, wide_color_support will be
- // set to true in this case.
- wide_color_support = true;
+ // Support for VK_GOOGLE_surfaceless_query.
// TODO(b/203826952): research proper value; temporarily use the
// values seen on Pixel
consumer_usage = AHARDWAREBUFFER_USAGE_COMPOSER_OVERLAY;
} else {
Surface& surface = *SurfaceFromHandle(surface_handle);
- int err = native_window_get_wide_color_support(surface.window.get(),
- &wide_color_support);
- if (err) {
- return VK_ERROR_SURFACE_LOST_KHR;
- }
- ALOGV("wide_color_support is: %d", wide_color_support);
-
consumer_usage = surface.consumer_usage;
}
- wide_color_support = wide_color_support && colorspace_ext;
AHardwareBuffer_Desc desc = {};
desc.width = 1;
@@ -796,9 +794,6 @@
VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_PASS_THROUGH_EXT});
all_formats.emplace_back(VkSurfaceFormatKHR{
VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_BT709_LINEAR_EXT});
- }
-
- if (wide_color_support) {
all_formats.emplace_back(VkSurfaceFormatKHR{
VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT});
all_formats.emplace_back(VkSurfaceFormatKHR{
@@ -828,8 +823,6 @@
all_formats.emplace_back(
VkSurfaceFormatKHR{VK_FORMAT_R16G16B16A16_SFLOAT,
VK_COLOR_SPACE_PASS_THROUGH_EXT});
- }
- if (wide_color_support) {
all_formats.emplace_back(
VkSurfaceFormatKHR{VK_FORMAT_R16G16B16A16_SFLOAT,
VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT});
@@ -848,8 +841,6 @@
all_formats.emplace_back(
VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32,
VK_COLOR_SPACE_PASS_THROUGH_EXT});
- }
- if (wide_color_support) {
all_formats.emplace_back(
VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32,
VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT});