Merge "Add HAL method to return SupportInfo object for PowerHAL" into main
diff --git a/Android.bp b/Android.bp
index 72311f0..13954ef 100644
--- a/Android.bp
+++ b/Android.bp
@@ -125,3 +125,9 @@
srcs: ["aidl/android/hardware/display/IDeviceProductInfoConstants.aidl"],
path: "aidl",
}
+
+dirgroup {
+ name: "trusty_dirgroup_frameworks_native",
+ dirs: ["libs/binder"],
+ visibility: ["//trusty/vendor/google/aosp/scripts"],
+}
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 9c01169..07d16f7 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -4,9 +4,6 @@
"name": "SurfaceFlinger_test",
"options": [
{
- "include-filter": "*"
- },
- {
// TODO(b/305717998): Deflake and re-enable
"exclude-filter": "*ChildLayerTest*"
}
@@ -23,12 +20,7 @@
],
"hwasan-postsubmit": [
{
- "name": "SurfaceFlinger_test",
- "options": [
- {
- "include-filter": "*"
- }
- ]
+ "name": "SurfaceFlinger_test"
}
]
}
diff --git a/cmds/dumpstate/DumpstateInternal.cpp b/cmds/dumpstate/DumpstateInternal.cpp
index 6f7fea3..ce7c55c 100644
--- a/cmds/dumpstate/DumpstateInternal.cpp
+++ b/cmds/dumpstate/DumpstateInternal.cpp
@@ -108,7 +108,7 @@
const uint32_t cap_syslog_mask = CAP_TO_MASK(CAP_SYSLOG);
const uint32_t cap_syslog_index = CAP_TO_INDEX(CAP_SYSLOG);
- bool has_cap_syslog = (capdata[cap_syslog_index].effective & cap_syslog_mask) != 0;
+ bool has_cap_syslog = (capdata[cap_syslog_index].permitted & cap_syslog_mask) != 0;
memset(&capdata, 0, sizeof(capdata));
if (has_cap_syslog) {
diff --git a/data/etc/android.hardware.xr.input.controller.xml b/data/etc/android.hardware.xr.input.controller.xml
new file mode 100644
index 0000000..1fb8b41
--- /dev/null
+++ b/data/etc/android.hardware.xr.input.controller.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 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.
+-->
+
+<!-- This is the standard feature to indicate the device supports
+ input from XR controllers. -->
+<permissions>
+ <feature name="android.hardware.xr.input.controller" />
+</permissions>
diff --git a/data/etc/android.hardware.xr.input.eye_tracking.xml b/data/etc/android.hardware.xr.input.eye_tracking.xml
new file mode 100644
index 0000000..8c6c2ed
--- /dev/null
+++ b/data/etc/android.hardware.xr.input.eye_tracking.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 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.
+-->
+
+<!-- This is the standard feature to indicate the device supports
+ input from an XR user's eyes. -->
+<permissions>
+ <feature name="android.hardware.xr.input.eye_tracking" />
+</permissions>
diff --git a/data/etc/android.hardware.xr.input.hand_tracking.xml b/data/etc/android.hardware.xr.input.hand_tracking.xml
new file mode 100644
index 0000000..6de3bee
--- /dev/null
+++ b/data/etc/android.hardware.xr.input.hand_tracking.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 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.
+-->
+
+<!-- This is the standard feature to indicate the device supports
+ input from an XR user's hands. -->
+<permissions>
+ <feature name="android.hardware.xr.input.hand_tracking" />
+</permissions>
diff --git a/data/etc/android.software.xr.api.openxr-1_0.xml b/data/etc/android.software.xr.api.openxr-1_0.xml
new file mode 100644
index 0000000..71c4a94
--- /dev/null
+++ b/data/etc/android.software.xr.api.openxr-1_0.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 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.
+-->
+
+<!-- This is the standard feature to indicate the device has a runtime
+ that supports OpenXR 1.0 (0x00010000). -->
+<permissions>
+ <feature name="android.software.xr.api.openxr" version="65536" />
+</permissions>
diff --git a/data/etc/android.software.xr.api.openxr-1_1.xml b/data/etc/android.software.xr.api.openxr-1_1.xml
new file mode 100644
index 0000000..45c1065
--- /dev/null
+++ b/data/etc/android.software.xr.api.openxr-1_1.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 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.
+-->
+
+<!-- This is the standard feature to indicate the device has a runtime
+ that supports OpenXR 1.1 (0x00010001). -->
+<permissions>
+ <feature name="android.software.xr.api.openxr" version="65537" />
+</permissions>
diff --git a/data/etc/android.software.xr.api.openxr-1_2.xml b/data/etc/android.software.xr.api.openxr-1_2.xml
new file mode 100644
index 0000000..ba11b8d
--- /dev/null
+++ b/data/etc/android.software.xr.api.openxr-1_2.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 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.
+-->
+
+<!-- This is the standard feature to indicate the device has a runtime
+ that supports OpenXR 1.2 (0x00010002). -->
+<permissions>
+ <feature name="android.software.xr.api.openxr" version="65538" />
+</permissions>
diff --git a/data/etc/android.software.xr.api.spatial-1.xml b/data/etc/android.software.xr.api.spatial-1.xml
new file mode 100644
index 0000000..ce425aa
--- /dev/null
+++ b/data/etc/android.software.xr.api.spatial-1.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 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.
+-->
+
+<!-- This is the standard feature to indicate the device has a runtime
+ that supports Android XR Spatial APIs, version 1. -->
+<permissions>
+ <feature name="android.software.xr.api.spatial" version="1" />
+</permissions>
diff --git a/include/input/InputConsumerNoResampling.h b/include/input/InputConsumerNoResampling.h
index 228347d..2e346bb 100644
--- a/include/input/InputConsumerNoResampling.h
+++ b/include/input/InputConsumerNoResampling.h
@@ -211,16 +211,17 @@
* `consumeBatchedInputEvents`.
*/
std::map<DeviceId, std::queue<InputMessage>> mBatches;
+
/**
- * Creates a MotionEvent by consuming samples from the provided queue. If one message has
- * eventTime > adjustedFrameTime, all subsequent messages in the queue will be skipped. It is
- * assumed that messages are queued in chronological order. In other words, only events that
- * occurred prior to the adjustedFrameTime will be consumed.
- * @param requestedFrameTime the time up to which to consume events.
- * @param messages the queue of messages to consume from
+ * Creates a MotionEvent by consuming samples from the provided queue. Consumes all messages
+ * with eventTime <= requestedFrameTime - resampleLatency, where `resampleLatency` is latency
+ * introduced by the resampler. Assumes that messages are queued in chronological order.
+ * @param requestedFrameTime The time up to which consume messages, as given by the inequality
+ * above. If std::nullopt, everything in messages will be consumed.
+ * @param messages the queue of messages to consume from.
*/
std::pair<std::unique_ptr<MotionEvent>, std::optional<uint32_t>> createBatchedMotionEvent(
- const nsecs_t requestedFrameTime, std::queue<InputMessage>& messages);
+ const std::optional<nsecs_t> requestedFrameTime, std::queue<InputMessage>& messages);
/**
* Consumes the batched input events, optionally allowing the caller to specify a device id
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 1a48239..6a248ef 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -266,6 +266,7 @@
public:
InputDeviceInfo();
InputDeviceInfo(const InputDeviceInfo& other);
+ InputDeviceInfo& operator=(const InputDeviceInfo& other);
~InputDeviceInfo();
struct MotionRange {
@@ -315,13 +316,11 @@
inline const InputDeviceViewBehavior& getViewBehavior() const { return mViewBehavior; }
- inline void setKeyCharacterMap(const std::shared_ptr<KeyCharacterMap> value) {
- mKeyCharacterMap = value;
+ inline void setKeyCharacterMap(std::unique_ptr<KeyCharacterMap> value) {
+ mKeyCharacterMap = std::move(value);
}
- inline const std::shared_ptr<KeyCharacterMap> getKeyCharacterMap() const {
- return mKeyCharacterMap;
- }
+ inline const KeyCharacterMap* getKeyCharacterMap() const { return mKeyCharacterMap.get(); }
inline void setVibrator(bool hasVibrator) { mHasVibrator = hasVibrator; }
inline bool hasVibrator() const { return mHasVibrator; }
@@ -364,7 +363,7 @@
std::optional<KeyboardLayoutInfo> mKeyboardLayoutInfo;
uint32_t mSources;
int32_t mKeyboardType;
- std::shared_ptr<KeyCharacterMap> mKeyCharacterMap;
+ std::unique_ptr<KeyCharacterMap> mKeyCharacterMap;
std::optional<InputDeviceUsiVersion> mUsiVersion;
ui::LogicalDisplayId mAssociatedDisplayId{ui::LogicalDisplayId::INVALID};
bool mEnabled;
diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h
index 7ea34c2..0a9e74f 100644
--- a/include/input/KeyCharacterMap.h
+++ b/include/input/KeyCharacterMap.h
@@ -72,7 +72,7 @@
};
/* Loads a key character map from a file. */
- static base::Result<std::shared_ptr<KeyCharacterMap>> load(const std::string& filename,
+ static base::Result<std::unique_ptr<KeyCharacterMap>> load(const std::string& filename,
Format format);
/* Loads a key character map from its string contents. */
diff --git a/include/input/Resampler.h b/include/input/Resampler.h
index 47519c2..6d95ca7 100644
--- a/include/input/Resampler.h
+++ b/include/input/Resampler.h
@@ -16,10 +16,14 @@
#pragma once
+#include <array>
#include <chrono>
+#include <iterator>
#include <optional>
#include <vector>
+#include <android-base/logging.h>
+#include <ftl/mixins.h>
#include <input/Input.h>
#include <input/InputTransport.h>
#include <input/RingBuffer.h>
@@ -79,13 +83,127 @@
PointerCoords coords;
};
+ /**
+ * Container that stores pointers as an associative array, supporting O(1) lookup by pointer id,
+ * as well as forward iteration in the order in which the pointer or pointers were inserted in
+ * the container. PointerMap has a maximum capacity equal to MAX_POINTERS.
+ */
+ class PointerMap {
+ public:
+ struct PointerId : ftl::DefaultConstructible<PointerId, int32_t>,
+ ftl::Equatable<PointerId> {
+ using DefaultConstructible::DefaultConstructible;
+ };
+
+ /**
+ * Custom iterator to enable use of range-based for loops.
+ */
+ template <typename T>
+ class iterator {
+ public:
+ using iterator_category = std::forward_iterator_tag;
+ using value_type = T;
+ using difference_type = std::ptrdiff_t;
+ using pointer = T*;
+ using reference = T&;
+
+ explicit iterator(pointer element) : mElement{element} {}
+
+ friend bool operator==(const iterator& lhs, const iterator& rhs) {
+ return lhs.mElement == rhs.mElement;
+ }
+
+ friend bool operator!=(const iterator& lhs, const iterator& rhs) {
+ return !(lhs == rhs);
+ }
+
+ iterator operator++() {
+ ++mElement;
+ return *this;
+ }
+
+ reference operator*() const { return *mElement; }
+
+ private:
+ pointer mElement;
+ };
+
+ PointerMap() {
+ idToIndex.fill(std::nullopt);
+ for (Pointer& pointer : pointers) {
+ pointer.properties.clear();
+ pointer.coords.clear();
+ }
+ }
+
+ /**
+ * Forward iterators to traverse the pointers in `pointers`. The order of the pointers is
+ * determined by the order in which they were inserted (not by id).
+ */
+ iterator<Pointer> begin() { return iterator<Pointer>{&pointers[0]}; }
+
+ iterator<const Pointer> begin() const { return iterator<const Pointer>{&pointers[0]}; }
+
+ iterator<Pointer> end() { return iterator<Pointer>{&pointers[nextPointerIndex]}; }
+
+ iterator<const Pointer> end() const {
+ return iterator<const Pointer>{&pointers[nextPointerIndex]};
+ }
+
+ /**
+ * Inserts the given pointer into the PointerMap. Precondition: The current number of
+ * contained pointers must be less than MAX_POINTERS when this function is called. It
+ * fatally logs if the user tries to insert more than MAX_POINTERS, or if pointer id is out
+ * of bounds.
+ */
+ void insert(const Pointer& pointer) {
+ LOG_IF(FATAL, nextPointerIndex >= pointers.size())
+ << "Cannot insert more than " << MAX_POINTERS << " in PointerMap.";
+ LOG_IF(FATAL, (pointer.properties.id < 0) || (pointer.properties.id > MAX_POINTER_ID))
+ << "Invalid pointer id.";
+ idToIndex[pointer.properties.id] = std::optional<size_t>{nextPointerIndex};
+ pointers[nextPointerIndex] = pointer;
+ ++nextPointerIndex;
+ }
+
+ /**
+ * Returns the pointer associated with the provided id if it exists.
+ * Otherwise, std::nullopt is returned.
+ */
+ std::optional<Pointer> find(PointerId id) const {
+ const int32_t idValue = ftl::to_underlying(id);
+ LOG_IF(FATAL, (idValue < 0) || (idValue > MAX_POINTER_ID)) << "Invalid pointer id.";
+ const std::optional<size_t> index = idToIndex[idValue];
+ return index.has_value() ? std::optional{pointers[*index]} : std::nullopt;
+ }
+
+ private:
+ /**
+ * The index at which a pointer is inserted in `pointers`. Likewise, it represents the
+ * number of pointers in PointerMap.
+ */
+ size_t nextPointerIndex{0};
+
+ /**
+ * Sequentially stores pointers. Each pointer's position is determined by the value of
+ * nextPointerIndex at insertion time.
+ */
+ std::array<Pointer, MAX_POINTERS + 1> pointers;
+
+ /**
+ * Maps each pointer id to its associated index in pointers. If no pointer with the id
+ * exists in pointers, the mapped value is std::nullopt.
+ */
+ std::array<std::optional<size_t>, MAX_POINTER_ID + 1> idToIndex;
+ };
+
struct Sample {
std::chrono::nanoseconds eventTime;
- std::vector<Pointer> pointers;
+ PointerMap pointerMap;
std::vector<PointerCoords> asPointerCoords() const {
std::vector<PointerCoords> pointersCoords;
- for (const Pointer& pointer : pointers) {
+ for (const Pointer& pointer : pointerMap) {
pointersCoords.push_back(pointer.coords);
}
return pointersCoords;
@@ -100,13 +218,12 @@
RingBuffer<Sample> mLatestSamples{/*capacity=*/2};
/**
- * Latest sample in mLatestSamples after resampling motion event. Used to compare if a pointer
- * does not move between samples.
+ * Latest sample in mLatestSamples after resampling motion event.
*/
std::optional<Sample> mLastRealSample;
/**
- * Latest prediction. Used to overwrite motion event samples if a set of conditions is met.
+ * Latest prediction. That is, the latest extrapolated sample.
*/
std::optional<Sample> mPreviousPrediction;
@@ -134,12 +251,12 @@
bool canInterpolate(const InputMessage& futureSample) const;
/**
- * Returns a sample interpolated between the latest sample of mLatestSamples and futureSample,
+ * Returns a sample interpolated between the latest sample of mLatestSamples and futureMessage,
* if the conditions from canInterpolate are satisfied. Otherwise, returns nullopt.
* mLatestSamples must have at least one sample when attemptInterpolation is called.
*/
std::optional<Sample> attemptInterpolation(std::chrono::nanoseconds resampleTime,
- const InputMessage& futureSample) const;
+ const InputMessage& futureMessage) const;
/**
* Checks if there are necessary conditions to extrapolate. That is, there are at least two
@@ -156,7 +273,8 @@
std::optional<Sample> attemptExtrapolation(std::chrono::nanoseconds resampleTime) const;
/**
- * Iterates through motion event samples, and calls overwriteStillPointers on each sample.
+ * Iterates through motion event samples, and replaces real coordinates with resampled
+ * coordinates to avoid jerkiness in certain conditions.
*/
void overwriteMotionEventSamples(MotionEvent& motionEvent) const;
@@ -174,4 +292,5 @@
inline static void addSampleToMotionEvent(const Sample& sample, MotionEvent& motionEvent);
};
+
} // namespace android
diff --git a/libs/binder/BackendUnifiedServiceManager.cpp b/libs/binder/BackendUnifiedServiceManager.cpp
index 52b485a..654cc0d 100644
--- a/libs/binder/BackendUnifiedServiceManager.cpp
+++ b/libs/binder/BackendUnifiedServiceManager.cpp
@@ -31,7 +31,8 @@
#endif
using AidlServiceManager = android::os::IServiceManager;
-using IAccessor = android::os::IAccessor;
+using android::os::IAccessor;
+using binder::Status;
static const char* kStaticCachableList[] = {
// go/keep-sorted start
@@ -39,10 +40,14 @@
"account",
"activity",
"alarm",
+ "android.frameworks.stats.IStats/default",
"android.system.keystore2.IKeystoreService/default",
"appops",
"audio",
+ "autofill",
+ "batteryproperties",
"batterystats",
+ "biometic",
"carrier_config",
"connectivity",
"content",
@@ -58,6 +63,7 @@
"jobscheduler",
"legacy_permission",
"location",
+ "lock_settings",
"media.extractor",
"media.metrics",
"media.player",
@@ -78,15 +84,19 @@
"phone",
"platform_compat",
"power",
+ "processinfo",
"role",
+ "sensitive_content_protection_service",
"sensorservice",
"statscompanion",
"telephony.registry",
"thermalservice",
"time_detector",
+ "tracing.proxy",
"trust",
"uimode",
"user",
+ "vibrator",
"virtualdevice",
"virtualdevice_native",
"webviewupdate",
@@ -109,19 +119,38 @@
return false;
}
-binder::Status BackendUnifiedServiceManager::updateCache(const std::string& serviceName,
- const os::Service& service) {
+Status BackendUnifiedServiceManager::updateCache(const std::string& serviceName,
+ const os::Service& service) {
if (!kUseCache) {
- return binder::Status::ok();
+ return Status::ok();
}
+ std::string traceStr;
+ if (atrace_is_tag_enabled(ATRACE_TAG_AIDL)) {
+ traceStr = "BinderCacheWithInvalidation::updateCache : " + serviceName;
+ }
+ binder::ScopedTrace aidlTrace(ATRACE_TAG_AIDL, traceStr.c_str());
+
if (service.getTag() == os::Service::Tag::binder) {
sp<IBinder> binder = service.get<os::Service::Tag::binder>();
- if (binder && mCacheForGetService->isClientSideCachingEnabled(serviceName) &&
- binder->isBinderAlive()) {
+ if (!binder) {
+ binder::ScopedTrace
+ aidlTrace(ATRACE_TAG_AIDL,
+ "BinderCacheWithInvalidation::updateCache failed: binder_null");
+ } else if (!binder->isBinderAlive()) {
+ binder::ScopedTrace aidlTrace(ATRACE_TAG_AIDL,
+ "BinderCacheWithInvalidation::updateCache failed: "
+ "isBinderAlive_false");
+ } else if (mCacheForGetService->isClientSideCachingEnabled(serviceName)) {
+ binder::ScopedTrace aidlTrace(ATRACE_TAG_AIDL,
+ "BinderCacheWithInvalidation::updateCache successful");
return mCacheForGetService->setItem(serviceName, binder);
+ } else {
+ binder::ScopedTrace aidlTrace(ATRACE_TAG_AIDL,
+ "BinderCacheWithInvalidation::updateCache failed: "
+ "caching_not_enabled");
}
}
- return binder::Status::ok();
+ return Status::ok();
}
bool BackendUnifiedServiceManager::returnIfCached(const std::string& serviceName,
@@ -143,25 +172,20 @@
mCacheForGetService = std::make_shared<BinderCacheWithInvalidation>();
}
-sp<AidlServiceManager> BackendUnifiedServiceManager::getImpl() {
- return mTheRealServiceManager;
-}
-
-binder::Status BackendUnifiedServiceManager::getService(const ::std::string& name,
- sp<IBinder>* _aidl_return) {
+Status BackendUnifiedServiceManager::getService(const ::std::string& name,
+ sp<IBinder>* _aidl_return) {
os::Service service;
- binder::Status status = getService2(name, &service);
+ Status status = getService2(name, &service);
*_aidl_return = service.get<os::Service::Tag::binder>();
return status;
}
-binder::Status BackendUnifiedServiceManager::getService2(const ::std::string& name,
- os::Service* _out) {
+Status BackendUnifiedServiceManager::getService2(const ::std::string& name, os::Service* _out) {
if (returnIfCached(name, _out)) {
- return binder::Status::ok();
+ return Status::ok();
}
os::Service service;
- binder::Status status = mTheRealServiceManager->getService2(name, &service);
+ Status status = mTheRealServiceManager->getService2(name, &service);
if (status.isOk()) {
status = toBinderService(name, service, _out);
@@ -172,14 +196,13 @@
return status;
}
-binder::Status BackendUnifiedServiceManager::checkService(const ::std::string& name,
- os::Service* _out) {
+Status BackendUnifiedServiceManager::checkService(const ::std::string& name, os::Service* _out) {
os::Service service;
if (returnIfCached(name, _out)) {
- return binder::Status::ok();
+ return Status::ok();
}
- binder::Status status = mTheRealServiceManager->checkService(name, &service);
+ Status status = mTheRealServiceManager->checkService(name, &service);
if (status.isOk()) {
status = toBinderService(name, service, _out);
if (status.isOk()) {
@@ -189,16 +212,15 @@
return status;
}
-binder::Status BackendUnifiedServiceManager::toBinderService(const ::std::string& name,
- const os::Service& in,
- os::Service* _out) {
+Status BackendUnifiedServiceManager::toBinderService(const ::std::string& name,
+ const os::Service& in, os::Service* _out) {
switch (in.getTag()) {
case os::Service::Tag::binder: {
if (in.get<os::Service::Tag::binder>() == nullptr) {
// failed to find a service. Check to see if we have any local
// injected Accessors for this service.
os::Service accessor;
- binder::Status status = getInjectedAccessor(name, &accessor);
+ Status status = getInjectedAccessor(name, &accessor);
if (!status.isOk()) {
*_out = os::Service::make<os::Service::Tag::binder>(nullptr);
return status;
@@ -214,7 +236,7 @@
}
*_out = in;
- return binder::Status::ok();
+ return Status::ok();
}
case os::Service::Tag::accessor: {
sp<IBinder> accessorBinder = in.get<os::Service::Tag::accessor>();
@@ -222,11 +244,11 @@
if (accessor == nullptr) {
ALOGE("Service#accessor doesn't have accessor. VM is maybe starting...");
*_out = os::Service::make<os::Service::Tag::binder>(nullptr);
- return binder::Status::ok();
+ return Status::ok();
}
auto request = [=] {
os::ParcelFileDescriptor fd;
- binder::Status ret = accessor->addConnection(&fd);
+ Status ret = accessor->addConnection(&fd);
if (ret.isOk()) {
return base::unique_fd(fd.release());
} else {
@@ -239,11 +261,11 @@
if (status != OK) {
ALOGE("Failed to set up preconnected binder RPC client: %s",
statusToString(status).c_str());
- return binder::Status::fromStatusT(status);
+ return Status::fromStatusT(status);
}
session->setSessionSpecificRoot(accessorBinder);
*_out = os::Service::make<os::Service::Tag::binder>(session->getRootObject());
- return binder::Status::ok();
+ return Status::ok();
}
default: {
LOG_ALWAYS_FATAL("Unknown service type: %d", in.getTag());
@@ -251,53 +273,52 @@
}
}
-binder::Status BackendUnifiedServiceManager::addService(const ::std::string& name,
- const sp<IBinder>& service,
- bool allowIsolated, int32_t dumpPriority) {
+Status BackendUnifiedServiceManager::addService(const ::std::string& name,
+ const sp<IBinder>& service, bool allowIsolated,
+ int32_t dumpPriority) {
return mTheRealServiceManager->addService(name, service, allowIsolated, dumpPriority);
}
-binder::Status BackendUnifiedServiceManager::listServices(
- int32_t dumpPriority, ::std::vector<::std::string>* _aidl_return) {
+Status BackendUnifiedServiceManager::listServices(int32_t dumpPriority,
+ ::std::vector<::std::string>* _aidl_return) {
return mTheRealServiceManager->listServices(dumpPriority, _aidl_return);
}
-binder::Status BackendUnifiedServiceManager::registerForNotifications(
+Status BackendUnifiedServiceManager::registerForNotifications(
const ::std::string& name, const sp<os::IServiceCallback>& callback) {
return mTheRealServiceManager->registerForNotifications(name, callback);
}
-binder::Status BackendUnifiedServiceManager::unregisterForNotifications(
+Status BackendUnifiedServiceManager::unregisterForNotifications(
const ::std::string& name, const sp<os::IServiceCallback>& callback) {
return mTheRealServiceManager->unregisterForNotifications(name, callback);
}
-binder::Status BackendUnifiedServiceManager::isDeclared(const ::std::string& name,
- bool* _aidl_return) {
+Status BackendUnifiedServiceManager::isDeclared(const ::std::string& name, bool* _aidl_return) {
return mTheRealServiceManager->isDeclared(name, _aidl_return);
}
-binder::Status BackendUnifiedServiceManager::getDeclaredInstances(
+Status BackendUnifiedServiceManager::getDeclaredInstances(
const ::std::string& iface, ::std::vector<::std::string>* _aidl_return) {
return mTheRealServiceManager->getDeclaredInstances(iface, _aidl_return);
}
-binder::Status BackendUnifiedServiceManager::updatableViaApex(
+Status BackendUnifiedServiceManager::updatableViaApex(
const ::std::string& name, ::std::optional<::std::string>* _aidl_return) {
return mTheRealServiceManager->updatableViaApex(name, _aidl_return);
}
-binder::Status BackendUnifiedServiceManager::getUpdatableNames(
- const ::std::string& apexName, ::std::vector<::std::string>* _aidl_return) {
+Status BackendUnifiedServiceManager::getUpdatableNames(const ::std::string& apexName,
+ ::std::vector<::std::string>* _aidl_return) {
return mTheRealServiceManager->getUpdatableNames(apexName, _aidl_return);
}
-binder::Status BackendUnifiedServiceManager::getConnectionInfo(
+Status BackendUnifiedServiceManager::getConnectionInfo(
const ::std::string& name, ::std::optional<os::ConnectionInfo>* _aidl_return) {
return mTheRealServiceManager->getConnectionInfo(name, _aidl_return);
}
-binder::Status BackendUnifiedServiceManager::registerClientCallback(
+Status BackendUnifiedServiceManager::registerClientCallback(
const ::std::string& name, const sp<IBinder>& service,
const sp<os::IClientCallback>& callback) {
return mTheRealServiceManager->registerClientCallback(name, service, callback);
}
-binder::Status BackendUnifiedServiceManager::tryUnregisterService(const ::std::string& name,
- const sp<IBinder>& service) {
+Status BackendUnifiedServiceManager::tryUnregisterService(const ::std::string& name,
+ const sp<IBinder>& service) {
return mTheRealServiceManager->tryUnregisterService(name, service);
}
-binder::Status BackendUnifiedServiceManager::getServiceDebugInfo(
+Status BackendUnifiedServiceManager::getServiceDebugInfo(
::std::vector<os::ServiceDebugInfo>* _aidl_return) {
return mTheRealServiceManager->getServiceDebugInfo(_aidl_return);
}
diff --git a/libs/binder/BackendUnifiedServiceManager.h b/libs/binder/BackendUnifiedServiceManager.h
index 47b2ec9..abc0eda 100644
--- a/libs/binder/BackendUnifiedServiceManager.h
+++ b/libs/binder/BackendUnifiedServiceManager.h
@@ -18,6 +18,7 @@
#include <android/os/BnServiceManager.h>
#include <android/os/IServiceManager.h>
#include <binder/IPCThreadState.h>
+#include <binder/Trace.h>
#include <map>
#include <memory>
@@ -59,6 +60,12 @@
}
bool removeItem(const std::string& key, const sp<IBinder>& who) {
+ std::string traceStr;
+ uint64_t tag = ATRACE_TAG_AIDL;
+ if (atrace_is_tag_enabled(tag)) {
+ traceStr = "BinderCacheWithInvalidation::removeItem " + key;
+ }
+ binder::ScopedTrace aidlTrace(tag, traceStr.c_str());
std::lock_guard<std::mutex> lock(mCacheMutex);
if (auto it = mCache.find(key); it != mCache.end()) {
if (it->second.service == who) {
@@ -81,11 +88,22 @@
if (item->localBinder() == nullptr) {
status_t status = item->linkToDeath(deathRecipient);
if (status != android::OK) {
+ std::string traceStr;
+ uint64_t tag = ATRACE_TAG_AIDL;
+ if (atrace_is_tag_enabled(tag)) {
+ traceStr =
+ "BinderCacheWithInvalidation::setItem Failed LinkToDeath for service " +
+ key + " : " + std::to_string(status);
+ }
+ binder::ScopedTrace aidlTrace(tag, traceStr.c_str());
+
ALOGE("Failed to linkToDeath binder for service %s. Error: %d", key.c_str(),
status);
return binder::Status::fromStatusT(status);
}
}
+ binder::ScopedTrace aidlTrace(ATRACE_TAG_AIDL,
+ "BinderCacheWithInvalidation::setItem Successfully Cached");
std::lock_guard<std::mutex> lock(mCacheMutex);
Entry entry = {.service = item, .deathRecipient = deathRecipient};
mCache[key] = entry;
@@ -103,7 +121,6 @@
public:
explicit BackendUnifiedServiceManager(const sp<os::IServiceManager>& impl);
- sp<os::IServiceManager> getImpl();
binder::Status getService(const ::std::string& name, sp<IBinder>* _aidl_return) override;
binder::Status getService2(const ::std::string& name, os::Service* out) override;
binder::Status checkService(const ::std::string& name, os::Service* out) override;
diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp
index c6b0cb7..bb03e89 100644
--- a/libs/binder/IMemory.cpp
+++ b/libs/binder/IMemory.cpp
@@ -330,8 +330,8 @@
if (err != NO_ERROR || // failed transaction
size != size64 || offset != offset64) { // ILP32 size check
ALOGE("binder=%p transaction failed fd=%d, size=%zu, err=%d (%s)",
- IInterface::asBinder(this).get(),
- parcel_fd, size, err, strerror(-err));
+ IInterface::asBinder(this).get(), parcel_fd, size, err,
+ statusToString(err).c_str());
return;
}
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 18c4134..96d821e 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -668,7 +668,8 @@
// FD was unowned in the source parcel.
int newFd = -1;
if (status_t status = binder::os::dupFileDescriptor(oldFd, &newFd); status != OK) {
- ALOGW("Failed to duplicate file descriptor %d: %s", oldFd, strerror(-status));
+ ALOGW("Failed to duplicate file descriptor %d: %s", oldFd,
+ statusToString(status).c_str());
}
rpcFields->mFds->emplace_back(unique_fd(newFd));
// Fixup the index in the data.
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index b8742af..c7851dc 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -503,7 +503,7 @@
auto status = binder::os::getRandomBytes(sessionId.data(), sessionId.size());
if (status != OK) {
- ALOGE("Failed to read random session ID: %s", strerror(-status));
+ ALOGE("Failed to read random session ID: %s", statusToString(status).c_str());
return;
}
} while (server->mSessions.end() != server->mSessions.find(sessionId));
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index cd21a91..16023ff 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -164,7 +164,7 @@
status_t status = mBootstrapTransport->interruptableWriteFully(mShutdownTrigger.get(), &iov,
1, std::nullopt, &fds);
if (status != OK) {
- ALOGE("Failed to send fd over bootstrap transport: %s", strerror(-status));
+ ALOGE("Failed to send fd over bootstrap transport: %s", statusToString(status).c_str());
return status;
}
diff --git a/libs/binder/ndk/binder_rpc.cpp b/libs/binder/ndk/binder_rpc.cpp
index 07b8c40..886eb4b 100644
--- a/libs/binder/ndk/binder_rpc.cpp
+++ b/libs/binder/ndk/binder_rpc.cpp
@@ -255,7 +255,7 @@
"new variant was added to the ABinderRpc_ConnectionInfo and this needs to be "
"updated.");
}
- return OK;
+ return STATUS_OK;
};
sp<IBinder> accessorBinder = android::createAccessor(String16(instance), std::move(generate));
if (accessorBinder == nullptr) {
@@ -321,7 +321,7 @@
// This AIBinder needs a strong ref to pass ownership to the caller
binder->incStrong(nullptr);
*outDelegator = binder.get();
- return OK;
+ return STATUS_OK;
}
ABinderRpc_ConnectionInfo* ABinderRpc_ConnectionInfo_new(const sockaddr* addr, socklen_t len) {
diff --git a/libs/binder/ndk/include_platform/android/binder_rpc.h b/libs/binder/ndk/include_platform/android/binder_rpc.h
index 9fe5d78..66667d3 100644
--- a/libs/binder/ndk/include_platform/android/binder_rpc.h
+++ b/libs/binder/ndk/include_platform/android/binder_rpc.h
@@ -287,6 +287,11 @@
* this object with one strong ref count and is responsible for removing
* that ref count with with AIBinder_decStrong when the caller wishes to
* drop the reference.
+ * \return STATUS_OK on success.
+ * STATUS_UNEXPECTED_NULL if instance or binder arguments are null.
+ * STATUS_BAD_TYPE if the binder is not an IAccessor.
+ * STATUS_NAME_NOT_FOUND if the binder is an IAccessor, but not
+ * associated with the provided instance name.
*/
binder_status_t ABinderRpc_Accessor_delegateAccessor(const char* _Nonnull instance,
AIBinder* _Nonnull binder,
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index 4545d7b..8404a48 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -16,7 +16,6 @@
"libdowncast_rs",
"liblibc",
"liblog_rust",
- "libnix",
],
host_supported: true,
vendor_available: true,
@@ -140,6 +139,9 @@
"--raw-line",
"use libc::sockaddr;",
],
+ cflags: [
+ "-DANDROID_PLATFORM",
+ ],
shared_libs: [
"libbinder_ndk",
],
@@ -180,6 +182,9 @@
// rustified
"libbinder_ndk_bindgen_flags.txt",
],
+ cflags: [
+ "-DANDROID_PLATFORM",
+ ],
shared_libs: [
"libbinder_ndk_on_trusty_mock",
"libc++",
@@ -200,7 +205,6 @@
"libdowncast_rs",
"liblibc",
"liblog_rust",
- "libnix",
],
}
diff --git a/libs/binder/rust/Cargo.toml b/libs/binder/rust/Cargo.toml
new file mode 100644
index 0000000..e5738c5
--- /dev/null
+++ b/libs/binder/rust/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "android-binder"
+version = "0.1.0"
+edition = "2021"
+description = "Safe bindings to Android Binder, restricted to the NDK"
+license = "Apache-2.0"
+
+[dependencies]
+binder-ndk-sys = { package = "android-binder-ndk-sys", version = "0.1", path = "./sys" }
+downcast-rs = "1.2.1"
+libc = "0.2.159"
+
+[lints.rust.unexpected_cfgs]
+level = "warn"
+check-cfg = ["cfg(android_vendor)", "cfg(android_ndk)", "cfg(android_vndk)", "cfg(trusty)"]
diff --git a/libs/binder/rust/build.rs b/libs/binder/rust/build.rs
new file mode 100644
index 0000000..f3e6b53
--- /dev/null
+++ b/libs/binder/rust/build.rs
@@ -0,0 +1,4 @@
+fn main() {
+ // Anything with cargo is NDK only. If you want to access anything else, use Soong.
+ println!("cargo::rustc-cfg=android_ndk");
+}
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 23026e5..8c0501b 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -207,8 +207,10 @@
/// Corresponds to TF_ONE_WAY -- an asynchronous call.
pub const FLAG_ONEWAY: TransactionFlags = sys::FLAG_ONEWAY;
/// Corresponds to TF_CLEAR_BUF -- clear transaction buffers after call is made.
+#[cfg(not(android_ndk))]
pub const FLAG_CLEAR_BUF: TransactionFlags = sys::FLAG_CLEAR_BUF;
/// Set to the vendor flag if we are building for the VNDK, 0 otherwise
+#[cfg(not(android_ndk))]
pub const FLAG_PRIVATE_LOCAL: TransactionFlags = sys::FLAG_PRIVATE_LOCAL;
/// Internal interface of binder local or remote objects for making
@@ -221,7 +223,7 @@
fn is_binder_alive(&self) -> bool;
/// Indicate that the service intends to receive caller security contexts.
- #[cfg(not(android_vndk))]
+ #[cfg(not(any(android_vndk, android_ndk)))]
fn set_requesting_sid(&mut self, enable: bool);
/// Dump this object to the given file handle
@@ -346,7 +348,6 @@
panic!("Expected non-null class pointer from AIBinder_Class_define!");
}
sys::AIBinder_Class_setOnDump(class, Some(I::on_dump));
- sys::AIBinder_Class_setHandleShellCommand(class, None);
class
};
InterfaceClass(ptr)
@@ -714,7 +715,7 @@
pub struct BinderFeatures {
/// Indicates that the service intends to receive caller security contexts. This must be true
/// for `ThreadState::with_calling_sid` to work.
- #[cfg(not(android_vndk))]
+ #[cfg(not(any(android_vndk, android_ndk)))]
pub set_requesting_sid: bool,
// Ensure that clients include a ..BinderFeatures::default() to preserve backwards compatibility
// when new fields are added. #[non_exhaustive] doesn't work because it prevents struct
@@ -916,8 +917,12 @@
impl $native {
/// Create a new binder service.
pub fn new_binder<T: $interface + Sync + Send + 'static>(inner: T, features: $crate::BinderFeatures) -> $crate::Strong<dyn $interface> {
+ #[cfg(not(android_ndk))]
let mut binder = $crate::binder_impl::Binder::new_with_stability($native(Box::new(inner)), $stability);
- #[cfg(not(android_vndk))]
+ #[cfg(android_ndk)]
+ let mut binder = $crate::binder_impl::Binder::new($native(Box::new(inner)));
+
+ #[cfg(not(any(android_vndk, android_ndk)))]
$crate::binder_impl::IBinderInternal::set_requesting_sid(&mut binder, features.set_requesting_sid);
$crate::Strong::new(Box::new(binder))
}
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index f7f3f35..14493db 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -100,11 +100,11 @@
mod native;
mod parcel;
mod proxy;
-#[cfg(not(trusty))]
+#[cfg(not(any(trusty, android_ndk)))]
mod service;
-#[cfg(not(trusty))]
+#[cfg(not(any(trusty, android_ndk)))]
mod state;
-#[cfg(not(any(android_vendor, android_vndk)))]
+#[cfg(not(any(android_vendor, android_ndk, android_vndk)))]
mod system_only;
use binder_ndk_sys as sys;
@@ -114,15 +114,18 @@
pub use error::{ExceptionCode, IntoBinderResult, Status, StatusCode};
pub use parcel::{ParcelFileDescriptor, Parcelable, ParcelableHolder};
pub use proxy::{DeathRecipient, SpIBinder, WpIBinder};
-#[cfg(not(trusty))]
+#[cfg(not(any(trusty, android_ndk)))]
pub use service::{
add_service, check_interface, check_service, force_lazy_services_persist,
- get_declared_instances, get_interface, get_service, is_declared, is_handling_transaction,
- register_lazy_service, wait_for_interface, wait_for_service, LazyServiceGuard,
+ get_declared_instances, is_declared, is_handling_transaction, register_lazy_service,
+ wait_for_interface, wait_for_service, LazyServiceGuard,
};
-#[cfg(not(trusty))]
+#[cfg(not(any(trusty, android_ndk)))]
+#[allow(deprecated)]
+pub use service::{get_interface, get_service};
+#[cfg(not(any(trusty, android_ndk)))]
pub use state::{ProcessState, ThreadState};
-#[cfg(not(any(android_vendor, android_vndk)))]
+#[cfg(not(any(android_vendor, android_vndk, android_ndk)))]
pub use system_only::{delegate_accessor, Accessor, ConnectionInfo};
/// Binder result containing a [`Status`] on error.
@@ -134,9 +137,10 @@
pub use crate::binder::{
IBinderInternal, InterfaceClass, LocalStabilityType, Remotable, Stability, StabilityType,
ToAsyncInterface, ToSyncInterface, TransactionCode, TransactionFlags, VintfStabilityType,
- FIRST_CALL_TRANSACTION, FLAG_CLEAR_BUF, FLAG_ONEWAY, FLAG_PRIVATE_LOCAL,
- LAST_CALL_TRANSACTION,
+ FIRST_CALL_TRANSACTION, FLAG_ONEWAY, LAST_CALL_TRANSACTION,
};
+ #[cfg(not(android_ndk))]
+ pub use crate::binder::{FLAG_CLEAR_BUF, FLAG_PRIVATE_LOCAL};
pub use crate::binder_async::BinderAsyncRuntime;
pub use crate::error::status_t;
pub use crate::native::Binder;
diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs
index c87cc94..9e1cfd6 100644
--- a/libs/binder/rust/src/native.rs
+++ b/libs/binder/rust/src/native.rs
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-use crate::binder::{
- AsNative, Interface, InterfaceClassMethods, Remotable, Stability, TransactionCode,
-};
+#[cfg(not(android_ndk))]
+use crate::binder::Stability;
+use crate::binder::{AsNative, Interface, InterfaceClassMethods, Remotable, TransactionCode};
use crate::error::{status_result, status_t, Result, StatusCode};
use crate::parcel::{BorrowedParcel, Serialize};
use crate::proxy::SpIBinder;
@@ -76,14 +76,32 @@
/// This moves the `rust_object` into an owned [`Box`] and Binder will
/// manage its lifetime.
pub fn new(rust_object: T) -> Binder<T> {
- Self::new_with_stability(rust_object, Stability::default())
+ #[cfg(not(android_ndk))]
+ {
+ Self::new_with_stability(rust_object, Stability::default())
+ }
+ #[cfg(android_ndk)]
+ {
+ Self::new_unmarked(rust_object)
+ }
}
/// Create a new Binder remotable object with the given stability
///
/// This moves the `rust_object` into an owned [`Box`] and Binder will
/// manage its lifetime.
+ #[cfg(not(android_ndk))]
pub fn new_with_stability(rust_object: T, stability: Stability) -> Binder<T> {
+ let mut binder = Self::new_unmarked(rust_object);
+ binder.mark_stability(stability);
+ binder
+ }
+
+ /// Creates a new Binder remotable object with unset stability
+ ///
+ /// This is internal because normally we want to set the stability explicitly,
+ /// however for the NDK variant we cannot mark the stability.
+ fn new_unmarked(rust_object: T) -> Binder<T> {
let class = T::get_class();
let rust_object = Box::into_raw(Box::new(rust_object));
// Safety: `AIBinder_new` expects a valid class pointer (which we
@@ -93,9 +111,7 @@
// decremented via `AIBinder_decStrong` when the reference lifetime
// ends.
let ibinder = unsafe { sys::AIBinder_new(class.into(), rust_object as *mut c_void) };
- let mut binder = Binder { ibinder, rust_object };
- binder.mark_stability(stability);
- binder
+ Binder { ibinder, rust_object }
}
/// Set the extension of a binder interface. This allows a downstream
@@ -189,6 +205,7 @@
}
/// Mark this binder object with the given stability guarantee
+ #[cfg(not(android_ndk))]
fn mark_stability(&mut self, stability: Stability) {
match stability {
Stability::Local => self.mark_local_stability(),
@@ -215,7 +232,7 @@
/// Mark this binder object with local stability, which is vendor if we are
/// building for android_vendor and system otherwise.
- #[cfg(not(android_vendor))]
+ #[cfg(not(any(android_vendor, android_ndk)))]
fn mark_local_stability(&mut self) {
// Safety: Self always contains a valid `AIBinder` pointer, so we can
// always call this C API safely.
diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs
index 3bfc425..485b0bd 100644
--- a/libs/binder/rust/src/parcel.rs
+++ b/libs/binder/rust/src/parcel.rs
@@ -197,6 +197,7 @@
// Data serialization methods
impl<'a> BorrowedParcel<'a> {
/// Data written to parcelable is zero'd before being deleted or reallocated.
+ #[cfg(not(android_ndk))]
pub fn mark_sensitive(&mut self) {
// Safety: guaranteed to have a parcel object, and this method never fails
unsafe { sys::AParcel_markSensitive(self.as_native()) }
@@ -342,6 +343,7 @@
impl Parcel {
/// Data written to parcelable is zero'd before being deleted or reallocated.
+ #[cfg(not(android_ndk))]
pub fn mark_sensitive(&mut self) {
self.borrowed().mark_sensitive()
}
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index 04f1517..593d12c 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -298,7 +298,7 @@
unsafe { sys::AIBinder_isAlive(self.as_native()) }
}
- #[cfg(not(android_vndk))]
+ #[cfg(not(any(android_vndk, android_ndk)))]
fn set_requesting_sid(&mut self, enable: bool) {
// Safety: `SpIBinder` guarantees that `self` always contains a valid
// pointer to an `AIBinder`.
diff --git a/libs/binder/rust/src/service.rs b/libs/binder/rust/src/service.rs
index 29dd8e1..f4fdcf5 100644
--- a/libs/binder/rust/src/service.rs
+++ b/libs/binder/rust/src/service.rs
@@ -176,6 +176,7 @@
/// seconds if it doesn't yet exist.
#[deprecated = "this polls 5s, use wait_for_interface or check_interface"]
pub fn get_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Strong<T>> {
+ #[allow(deprecated)]
interface_cast(get_service(name))
}
diff --git a/libs/binder/rust/src/system_only.rs b/libs/binder/rust/src/system_only.rs
index 08582ab..9833cbe 100644
--- a/libs/binder/rust/src/system_only.rs
+++ b/libs/binder/rust/src/system_only.rs
@@ -22,10 +22,9 @@
use std::ffi::{c_void, CStr, CString};
use std::os::raw::c_char;
-use libc::sockaddr;
-use nix::sys::socket::{SockaddrLike, UnixAddr, VsockAddr};
+use libc::{sockaddr, sockaddr_un, sockaddr_vm, socklen_t};
use std::sync::Arc;
-use std::{fmt, ptr};
+use std::{fmt, mem, ptr};
/// Rust wrapper around ABinderRpc_Accessor objects for RPC binder service management.
///
@@ -44,9 +43,9 @@
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ConnectionInfo {
/// For vsock connection
- Vsock(VsockAddr),
+ Vsock(sockaddr_vm),
/// For unix domain socket connection
- Unix(UnixAddr),
+ Unix(sockaddr_un),
}
/// Safety: A `Accessor` is a wrapper around `ABinderRpc_Accessor` which is
@@ -148,13 +147,21 @@
match connection {
ConnectionInfo::Vsock(addr) => {
// Safety: The sockaddr is being copied in the NDK API
- unsafe { sys::ABinderRpc_ConnectionInfo_new(addr.as_ptr(), addr.len()) }
+ unsafe {
+ sys::ABinderRpc_ConnectionInfo_new(
+ &addr as *const sockaddr_vm as *const sockaddr,
+ mem::size_of::<sockaddr_vm>() as socklen_t,
+ )
+ }
}
ConnectionInfo::Unix(addr) => {
// Safety: The sockaddr is being copied in the NDK API
// The cast is from sockaddr_un* to sockaddr*.
unsafe {
- sys::ABinderRpc_ConnectionInfo_new(addr.as_ptr() as *const sockaddr, addr.len())
+ sys::ABinderRpc_ConnectionInfo_new(
+ &addr as *const sockaddr_un as *const sockaddr,
+ mem::size_of::<sockaddr_un>() as socklen_t,
+ )
}
}
}
diff --git a/libs/binder/rust/sys/BinderBindings.hpp b/libs/binder/rust/sys/BinderBindings.hpp
index bd666fe..557f0e8 100644
--- a/libs/binder/rust/sys/BinderBindings.hpp
+++ b/libs/binder/rust/sys/BinderBindings.hpp
@@ -15,15 +15,19 @@
*/
#include <android/binder_ibinder.h>
+#include <android/binder_parcel.h>
+#include <android/binder_status.h>
+
+/* Platform only */
+#if defined(ANDROID_PLATFORM) || defined(__ANDROID_VENDOR__)
#include <android/binder_ibinder_platform.h>
#include <android/binder_manager.h>
-#include <android/binder_parcel.h>
#include <android/binder_parcel_platform.h>
#include <android/binder_process.h>
#include <android/binder_rpc.h>
#include <android/binder_shell.h>
#include <android/binder_stability.h>
-#include <android/binder_status.h>
+#endif
namespace android {
@@ -81,8 +85,10 @@
enum {
FLAG_ONEWAY = FLAG_ONEWAY,
+#if defined(ANDROID_PLATFORM) || defined(__ANDROID_VENDOR__)
FLAG_CLEAR_BUF = FLAG_CLEAR_BUF,
FLAG_PRIVATE_LOCAL = FLAG_PRIVATE_LOCAL,
+#endif
};
} // namespace consts
diff --git a/libs/binder/rust/sys/Cargo.toml b/libs/binder/rust/sys/Cargo.toml
new file mode 100644
index 0000000..ad8e9c2
--- /dev/null
+++ b/libs/binder/rust/sys/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "android-binder-ndk-sys"
+version = "0.1.0"
+edition = "2021"
+description = "Bindgen bindings to android binder, restricted to the NDK"
+license = "Apache-2.0"
+
+[dependencies]
+
+[lib]
+path = "lib.rs"
+
+[build-dependencies]
+bindgen = "0.70.1"
diff --git a/libs/binder/rust/sys/build.rs b/libs/binder/rust/sys/build.rs
new file mode 100644
index 0000000..cb9c65b
--- /dev/null
+++ b/libs/binder/rust/sys/build.rs
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+use std::env;
+use std::path::PathBuf;
+
+fn main() {
+ let ndk_home = PathBuf::from(env::var("ANDROID_NDK_HOME").unwrap());
+ let toolchain = ndk_home.join("toolchains/llvm/prebuilt/linux-x86_64/");
+ let sysroot = toolchain.join("sysroot");
+ let bindings = bindgen::Builder::default()
+ .clang_arg(format!("--sysroot={}", sysroot.display()))
+ // TODO figure out what the "standard" #define is and use that instead
+ .header("BinderBindings.hpp")
+ .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
+ // Keep in sync with libbinder_ndk_bindgen_flags.txt
+ .default_enum_style(bindgen::EnumVariation::Rust { non_exhaustive: true })
+ .constified_enum("android::c_interface::consts::.*")
+ .allowlist_type("android::c_interface::.*")
+ .allowlist_type("AStatus")
+ .allowlist_type("AIBinder_Class")
+ .allowlist_type("AIBinder")
+ .allowlist_type("AIBinder_Weak")
+ .allowlist_type("AIBinder_DeathRecipient")
+ .allowlist_type("AParcel")
+ .allowlist_type("binder_status_t")
+ .blocklist_function("vprintf")
+ .blocklist_function("strtold")
+ .blocklist_function("_vtlog")
+ .blocklist_function("vscanf")
+ .blocklist_function("vfprintf_worker")
+ .blocklist_function("vsprintf")
+ .blocklist_function("vsnprintf")
+ .blocklist_function("vsnprintf_filtered")
+ .blocklist_function("vfscanf")
+ .blocklist_function("vsscanf")
+ .blocklist_function("vdprintf")
+ .blocklist_function("vasprintf")
+ .blocklist_function("strtold_l")
+ .allowlist_function(".*")
+ .generate()
+ .expect("Couldn't generate bindings");
+ let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
+ bindings.write_to_file(out_path.join("bindings.rs")).expect("Couldn't write bindings.");
+ println!("cargo::rustc-link-lib=binder_ndk");
+}
diff --git a/libs/binder/rust/sys/lib.rs b/libs/binder/rust/sys/lib.rs
index 5352473..349e5a9 100644
--- a/libs/binder/rust/sys/lib.rs
+++ b/libs/binder/rust/sys/lib.rs
@@ -20,6 +20,7 @@
use std::fmt;
#[cfg(not(target_os = "trusty"))]
+#[allow(bad_style)]
mod bindings {
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 25e6a52..49f4cba 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -50,9 +50,28 @@
using namespace std::chrono_literals;
namespace {
+
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+// RAII wrapper to defer arbitrary work until the Deferred instance is deleted.
+template <class F>
+class Deferred {
+public:
+ explicit Deferred(F f) : mF{std::move(f)} {}
+
+ ~Deferred() { mF(); }
+
+ Deferred(const Deferred&) = delete;
+ Deferred& operator=(const Deferred&) = delete;
+
+private:
+ F mF;
+};
+#endif
+
inline const char* boolToString(bool b) {
return b ? "true" : "false";
}
+
} // namespace
namespace android {
@@ -77,12 +96,6 @@
std::unique_lock _lock{mutex}; \
base::ScopedLockAssertion assumeLocked(mutex);
-#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
-static ReleaseBufferCallback EMPTY_RELEASE_CALLBACK =
- [](const ReleaseCallbackId&, const sp<Fence>& /*releaseFence*/,
- std::optional<uint32_t> /*currentMaxAcquiredBufferCount*/) {};
-#endif
-
void BLASTBufferItemConsumer::onDisconnect() {
Mutex::Autolock lock(mMutex);
mPreviouslyConnected = mCurrentlyConnected;
@@ -225,9 +238,8 @@
this);
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
- std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint> bufferReleaseConsumer;
- gui::BufferReleaseChannel::open(mName, bufferReleaseConsumer, mBufferReleaseProducer);
- mBufferReleaseReader = std::make_shared<BufferReleaseReader>(std::move(bufferReleaseConsumer));
+ gui::BufferReleaseChannel::open(mName, mBufferReleaseConsumer, mBufferReleaseProducer);
+ mBufferReleaseReader.emplace(*this);
#endif
BQA_LOGV("BLASTBufferQueue created");
@@ -260,7 +272,7 @@
// safe default, most producers are expected to override this
mProducer->setMaxDequeuedBufferCount(2);
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
- mBufferReleaseThread.start(sp<BLASTBufferQueue>::fromExisting(this));
+ mBufferReleaseThread.emplace(sp<BLASTBufferQueue>::fromExisting(this));
#endif
}
@@ -636,7 +648,7 @@
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
ReleaseBufferCallback releaseBufferCallback =
- applyTransaction ? EMPTY_RELEASE_CALLBACK : makeReleaseBufferCallbackThunk();
+ applyTransaction ? nullptr : makeReleaseBufferCallbackThunk();
#else
auto releaseBufferCallback = makeReleaseBufferCallbackThunk();
#endif
@@ -1137,6 +1149,24 @@
#endif
};
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+class BBQBufferQueueCore : public BufferQueueCore {
+public:
+ explicit BBQBufferQueueCore(const wp<BLASTBufferQueue>& bbq) : mBLASTBufferQueue{bbq} {}
+
+ void notifyBufferReleased() const override {
+ sp<BLASTBufferQueue> bbq = mBLASTBufferQueue.promote();
+ if (!bbq) {
+ return;
+ }
+ bbq->mBufferReleaseReader->interruptBlockingRead();
+ }
+
+private:
+ wp<BLASTBufferQueue> mBLASTBufferQueue;
+};
+#endif
+
// Extends the BufferQueueProducer to create a wrapper around the listener so the listener calls
// can be non-blocking when the producer is in the client process.
class BBQBufferQueueProducer : public BufferQueueProducer {
@@ -1188,6 +1218,44 @@
return BufferQueueProducer::query(what, value);
}
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+ status_t waitForBufferRelease(std::unique_lock<std::mutex>& bufferQueueLock,
+ nsecs_t timeout) const override {
+ sp<BLASTBufferQueue> bbq = mBLASTBufferQueue.promote();
+ if (!bbq) {
+ return OK;
+ }
+
+ // BufferQueue has already checked if we have a free buffer. If there's an unread interrupt,
+ // we want to ignore it. This must be done before unlocking the BufferQueue lock to ensure
+ // we don't miss an interrupt.
+ bbq->mBufferReleaseReader->clearInterrupts();
+ bbq->mThreadsBlockingOnDequeue++;
+ bufferQueueLock.unlock();
+ Deferred cleanup{[&]() {
+ bufferQueueLock.lock();
+ bbq->mThreadsBlockingOnDequeue--;
+ }};
+
+ ATRACE_FORMAT("waiting for free buffer");
+ ReleaseCallbackId id;
+ sp<Fence> fence;
+ uint32_t maxAcquiredBufferCount;
+ status_t status =
+ bbq->mBufferReleaseReader->readBlocking(id, fence, maxAcquiredBufferCount, timeout);
+ if (status == TIMED_OUT) {
+ return TIMED_OUT;
+ } else if (status != OK) {
+ // Waiting was interrupted or an error occurred. BufferQueueProducer will check if we
+ // have a free buffer and call this method again if not.
+ return OK;
+ }
+
+ bbq->releaseBufferCallback(id, fence, maxAcquiredBufferCount);
+ return OK;
+ }
+#endif
+
private:
const wp<BLASTBufferQueue> mBLASTBufferQueue;
};
@@ -1201,14 +1269,18 @@
LOG_ALWAYS_FATAL_IF(outProducer == nullptr, "BLASTBufferQueue: outProducer must not be NULL");
LOG_ALWAYS_FATAL_IF(outConsumer == nullptr, "BLASTBufferQueue: outConsumer must not be NULL");
- sp<BufferQueueCore> core(new BufferQueueCore());
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+ auto core = sp<BBQBufferQueueCore>::make(this);
+#else
+ auto core = sp<BufferQueueCore>::make();
+#endif
LOG_ALWAYS_FATAL_IF(core == nullptr, "BLASTBufferQueue: failed to create BufferQueueCore");
- sp<IGraphicBufferProducer> producer(new BBQBufferQueueProducer(core, this));
+ auto producer = sp<BBQBufferQueueProducer>::make(core, this);
LOG_ALWAYS_FATAL_IF(producer == nullptr,
"BLASTBufferQueue: failed to create BBQBufferQueueProducer");
- sp<BufferQueueConsumer> consumer(new BufferQueueConsumer(core));
+ auto consumer = sp<BufferQueueConsumer>::make(core);
consumer->setAllowExtraAcquire(true);
LOG_ALWAYS_FATAL_IF(consumer == nullptr,
"BLASTBufferQueue: failed to create BufferQueueConsumer");
@@ -1273,10 +1345,8 @@
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
-BLASTBufferQueue::BufferReleaseReader::BufferReleaseReader(
- std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint> endpoint)
- : mEndpoint{std::move(endpoint)} {
- mEpollFd = android::base::unique_fd{epoll_create1(0)};
+BLASTBufferQueue::BufferReleaseReader::BufferReleaseReader(BLASTBufferQueue& bbq) : mBbq{bbq} {
+ mEpollFd = android::base::unique_fd{epoll_create1(EPOLL_CLOEXEC)};
LOG_ALWAYS_FATAL_IF(!mEpollFd.ok(),
"Failed to create buffer release epoll file descriptor. errno=%d "
"message='%s'",
@@ -1284,9 +1354,9 @@
epoll_event registerEndpointFd{};
registerEndpointFd.events = EPOLLIN;
- registerEndpointFd.data.fd = mEndpoint->getFd();
- status_t status =
- epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mEndpoint->getFd(), ®isterEndpointFd);
+ registerEndpointFd.data.fd = mBbq.mBufferReleaseConsumer->getFd();
+ status_t status = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mBbq.mBufferReleaseConsumer->getFd(),
+ ®isterEndpointFd);
LOG_ALWAYS_FATAL_IF(status == -1,
"Failed to register buffer release consumer file descriptor with epoll. "
"errno=%d message='%s'",
@@ -1308,78 +1378,153 @@
errno, strerror(errno));
}
-BLASTBufferQueue::BufferReleaseReader& BLASTBufferQueue::BufferReleaseReader::operator=(
- BufferReleaseReader&& other) {
- if (this != &other) {
- ftl::FakeGuard guard{mMutex};
- ftl::FakeGuard otherGuard{other.mMutex};
- mEndpoint = std::move(other.mEndpoint);
- mEpollFd = std::move(other.mEpollFd);
- mEventFd = std::move(other.mEventFd);
- }
- return *this;
-}
-
status_t BLASTBufferQueue::BufferReleaseReader::readBlocking(ReleaseCallbackId& outId,
sp<Fence>& outFence,
- uint32_t& outMaxAcquiredBufferCount) {
+ uint32_t& outMaxAcquiredBufferCount,
+ nsecs_t timeout) {
+ // TODO(b/363290953) epoll_wait only has millisecond timeout precision. If timeout is less than
+ // 1ms, then we round timeout up to 1ms. Otherwise, we round timeout to the nearest
+ // millisecond. Once epoll_pwait2 can be used in libgui, we can specify timeout with nanosecond
+ // precision.
+ int timeoutMs = -1;
+ if (timeout == 0) {
+ timeoutMs = 0;
+ } else if (timeout > 0) {
+ const int nsPerMs = 1000000;
+ if (timeout < nsPerMs) {
+ timeoutMs = 1;
+ } else {
+ timeoutMs = static_cast<int>(
+ std::chrono::round<std::chrono::milliseconds>(std::chrono::nanoseconds{timeout})
+ .count());
+ }
+ }
+
epoll_event event{};
- while (true) {
- int eventCount = epoll_wait(mEpollFd.get(), &event, 1 /* maxevents */, -1 /* timeout */);
- if (eventCount == 1) {
- break;
- }
- if (eventCount == -1 && errno != EINTR) {
- ALOGE("epoll_wait error while waiting for buffer release. errno=%d message='%s'", errno,
- strerror(errno));
- }
+ int eventCount;
+ do {
+ eventCount = epoll_wait(mEpollFd.get(), &event, 1 /*maxevents*/, timeoutMs);
+ } while (eventCount == -1 && errno != EINTR);
+
+ if (eventCount == -1) {
+ ALOGE("epoll_wait error while waiting for buffer release. errno=%d message='%s'", errno,
+ strerror(errno));
+ return UNKNOWN_ERROR;
+ }
+
+ if (eventCount == 0) {
+ return TIMED_OUT;
}
if (event.data.fd == mEventFd.get()) {
- uint64_t value;
- if (read(mEventFd.get(), &value, sizeof(uint64_t)) == -1 && errno != EWOULDBLOCK) {
- ALOGE("error while reading from eventfd. errno=%d message='%s'", errno,
- strerror(errno));
- }
+ clearInterrupts();
return WOULD_BLOCK;
}
- std::lock_guard lock{mMutex};
- return mEndpoint->readReleaseFence(outId, outFence, outMaxAcquiredBufferCount);
+ return mBbq.mBufferReleaseConsumer->readReleaseFence(outId, outFence,
+ outMaxAcquiredBufferCount);
}
void BLASTBufferQueue::BufferReleaseReader::interruptBlockingRead() {
- uint64_t value = 1;
- if (write(mEventFd.get(), &value, sizeof(uint64_t)) == -1) {
+ if (eventfd_write(mEventFd.get(), 1) == -1) {
ALOGE("failed to notify dequeue event. errno=%d message='%s'", errno, strerror(errno));
}
}
-void BLASTBufferQueue::BufferReleaseThread::start(const sp<BLASTBufferQueue>& bbq) {
- mRunning = std::make_shared<std::atomic_bool>(true);
- mReader = bbq->mBufferReleaseReader;
- std::thread([running = mRunning, reader = mReader, weakBbq = wp<BLASTBufferQueue>(bbq)]() {
+void BLASTBufferQueue::BufferReleaseReader::clearInterrupts() {
+ eventfd_t value;
+ if (eventfd_read(mEventFd.get(), &value) == -1 && errno != EWOULDBLOCK) {
+ ALOGE("error while reading from eventfd. errno=%d message='%s'", errno, strerror(errno));
+ }
+}
+
+BLASTBufferQueue::BufferReleaseThread::BufferReleaseThread(const sp<BLASTBufferQueue>& bbq) {
+ android::base::unique_fd epollFd{epoll_create1(EPOLL_CLOEXEC)};
+ LOG_ALWAYS_FATAL_IF(!epollFd.ok(),
+ "Failed to create buffer release background thread epoll file descriptor. "
+ "errno=%d message='%s'",
+ errno, strerror(errno));
+
+ epoll_event registerEndpointFd{};
+ registerEndpointFd.events = EPOLLIN;
+ registerEndpointFd.data.fd = bbq->mBufferReleaseConsumer->getFd();
+ status_t status = epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, bbq->mBufferReleaseConsumer->getFd(),
+ ®isterEndpointFd);
+ LOG_ALWAYS_FATAL_IF(status == -1,
+ "Failed to register background thread buffer release consumer file "
+ "descriptor with epoll. errno=%d message='%s'",
+ errno, strerror(errno));
+
+ // EventFd is used to break the background thread's loop.
+ android::base::unique_fd eventFd{eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)};
+ LOG_ALWAYS_FATAL_IF(!eventFd.ok(),
+ "Failed to create background thread buffer release event file descriptor. "
+ "errno=%d message='%s'",
+ errno, strerror(errno));
+
+ epoll_event registerEventFd{};
+ registerEventFd.events = EPOLLIN;
+ registerEventFd.data.fd = eventFd.get();
+ status = epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), ®isterEventFd);
+ LOG_ALWAYS_FATAL_IF(status == -1,
+ "Failed to register background thread event file descriptor with epoll. "
+ "errno=%d message='%s'",
+ errno, strerror(errno));
+
+ mEventFd = eventFd.get();
+
+ std::thread([epollFd = std::move(epollFd), eventFd = std::move(eventFd),
+ weakBbq = wp<BLASTBufferQueue>(bbq)]() {
pthread_setname_np(pthread_self(), "BufferReleaseThread");
- while (*running) {
- ReleaseCallbackId id;
- sp<Fence> fence;
- uint32_t maxAcquiredBufferCount;
- if (status_t status = reader->readBlocking(id, fence, maxAcquiredBufferCount);
- status != OK) {
+ while (true) {
+ epoll_event event{};
+ int eventCount;
+ do {
+ eventCount = epoll_wait(epollFd.get(), &event, 1 /*maxevents*/, -1 /*timeout*/);
+ } while (eventCount == -1 && errno != EINTR);
+
+ if (eventCount == -1) {
+ ALOGE("epoll_wait error while waiting for buffer release in background thread. "
+ "errno=%d message='%s'",
+ errno, strerror(errno));
continue;
}
+
+ // EventFd is used to join this thread.
+ if (event.data.fd == eventFd.get()) {
+ return;
+ }
+
sp<BLASTBufferQueue> bbq = weakBbq.promote();
if (!bbq) {
return;
}
+
+ // If there are threads blocking on dequeue, give those threads priority for handling
+ // the release.
+ if (bbq->mThreadsBlockingOnDequeue > 0) {
+ std::this_thread::sleep_for(0ms);
+ continue;
+ }
+
+ ReleaseCallbackId id;
+ sp<Fence> fence;
+ uint32_t maxAcquiredBufferCount;
+ status_t status = bbq->mBufferReleaseConsumer->readReleaseFence(id, fence,
+ maxAcquiredBufferCount);
+ if (status != OK) {
+ ALOGE("failed to read from buffer release consumer in background thread. errno=%d "
+ "message='%s'",
+ errno, strerror(errno));
+ continue;
+ }
bbq->releaseBufferCallback(id, fence, maxAcquiredBufferCount);
}
}).detach();
}
BLASTBufferQueue::BufferReleaseThread::~BufferReleaseThread() {
- *mRunning = false;
- mReader->interruptBlockingRead();
+ eventfd_write(mEventFd, 1);
}
#endif
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 69d25be..d0607bf 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -297,7 +297,11 @@
// We might have freed a slot while dropping old buffers, or the producer
// may be blocked waiting for the number of buffers in the queue to
// decrease.
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+ mCore->notifyBufferReleased();
+#else
mCore->mDequeueCondition.notify_all();
+#endif
ATRACE_INT(mCore->mConsumerName.c_str(), static_cast<int32_t>(mCore->mQueue.size()));
#ifndef NO_BINDER
@@ -350,7 +354,12 @@
mCore->mActiveBuffers.erase(slot);
mCore->mFreeSlots.insert(slot);
mCore->clearBufferSlotLocked(slot);
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+ mCore->notifyBufferReleased();
+#else
mCore->mDequeueCondition.notify_all();
+#endif
+
VALIDATE_CONSISTENCY();
}
@@ -520,7 +529,12 @@
}
BQ_LOGV("releaseBuffer: releasing slot %d", slot);
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+ mCore->notifyBufferReleased();
+#else
mCore->mDequeueCondition.notify_all();
+#endif
+
VALIDATE_CONSISTENCY();
} // Autolock scope
@@ -574,7 +588,11 @@
mCore->mQueue.clear();
mCore->freeAllBuffersLocked();
mCore->mSharedBufferSlot = BufferQueueCore::INVALID_BUFFER_SLOT;
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+ mCore->notifyBufferReleased();
+#else
mCore->mDequeueCondition.notify_all();
+#endif
return NO_ERROR;
}
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index e0c5b1f..d52cf70 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -371,6 +371,12 @@
}
}
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+void BufferQueueCore::notifyBufferReleased() const {
+ mDequeueCondition.notify_all();
+}
+#endif
+
#if DEBUG_ONLY_CODE
void BufferQueueCore::validateConsistencyLocked() const {
static const useconds_t PAUSE_TIME = 0;
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index da74e9c..473a374 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -202,7 +202,11 @@
if (delta < 0) {
listener = mCore->mConsumerListener;
}
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+ mCore->notifyBufferReleased();
+#else
mCore->mDequeueCondition.notify_all();
+#endif
} // Autolock scope
// Call back without lock held
@@ -254,7 +258,12 @@
}
mCore->mAsyncMode = async;
VALIDATE_CONSISTENCY();
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+ mCore->notifyBufferReleased();
+#else
mCore->mDequeueCondition.notify_all();
+#endif
+
if (delta < 0) {
listener = mCore->mConsumerListener;
}
@@ -376,6 +385,12 @@
(acquiredCount <= mCore->mMaxAcquiredBufferCount)) {
return WOULD_BLOCK;
}
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+ if (status_t status = waitForBufferRelease(lock, mDequeueTimeout);
+ status == TIMED_OUT) {
+ return TIMED_OUT;
+ }
+#else
if (mDequeueTimeout >= 0) {
std::cv_status result = mCore->mDequeueCondition.wait_for(lock,
std::chrono::nanoseconds(mDequeueTimeout));
@@ -385,12 +400,29 @@
} else {
mCore->mDequeueCondition.wait(lock);
}
+#endif
}
} // while (tryAgain)
return NO_ERROR;
}
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+status_t BufferQueueProducer::waitForBufferRelease(std::unique_lock<std::mutex>& lock,
+ nsecs_t timeout) const {
+ if (mDequeueTimeout >= 0) {
+ std::cv_status result =
+ mCore->mDequeueCondition.wait_for(lock, std::chrono::nanoseconds(timeout));
+ if (result == std::cv_status::timeout) {
+ return TIMED_OUT;
+ }
+ } else {
+ mCore->mDequeueCondition.wait(lock);
+ }
+ return OK;
+}
+#endif
+
status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* outFence,
uint32_t width, uint32_t height, PixelFormat format,
uint64_t usage, uint64_t* outBufferAge,
@@ -741,7 +773,11 @@
mCore->mActiveBuffers.erase(slot);
mCore->mFreeSlots.insert(slot);
mCore->clearBufferSlotLocked(slot);
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+ mCore->notifyBufferReleased();
+#else
mCore->mDequeueCondition.notify_all();
+#endif
VALIDATE_CONSISTENCY();
}
@@ -1082,7 +1118,11 @@
}
mCore->mBufferHasBeenQueued = true;
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+ mCore->notifyBufferReleased();
+#else
mCore->mDequeueCondition.notify_all();
+#endif
mCore->mLastQueuedSlot = slot;
output->width = mCore->mDefaultWidth;
@@ -1218,7 +1258,11 @@
bufferId = gb->getId();
}
mSlots[slot].mFence = fence;
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+ mCore->notifyBufferReleased();
+#else
mCore->mDequeueCondition.notify_all();
+#endif
listener = mCore->mConsumerListener;
VALIDATE_CONSISTENCY();
}
@@ -1457,7 +1501,11 @@
mCore->mConnectedApi = BufferQueueCore::NO_CONNECTED_API;
mCore->mConnectedPid = -1;
mCore->mSidebandStream.clear();
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+ mCore->notifyBufferReleased();
+#else
mCore->mDequeueCondition.notify_all();
+#endif
mCore->mAutoPrerotation = false;
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)
mCore->mAdditionalOptions.clear();
@@ -1508,7 +1556,6 @@
const bool useDefaultSize = !width && !height;
while (true) {
- size_t newBufferCount = 0;
uint32_t allocWidth = 0;
uint32_t allocHeight = 0;
PixelFormat allocFormat = PIXEL_FORMAT_UNKNOWN;
@@ -1530,8 +1577,9 @@
// Only allocate one buffer at a time to reduce risks of overlapping an allocation from
// both allocateBuffers and dequeueBuffer.
- newBufferCount = mCore->mFreeSlots.empty() ? 0 : 1;
- if (newBufferCount == 0) {
+ if (mCore->mFreeSlots.empty()) {
+ BQ_LOGV("allocateBuffers: a slot was occupied while "
+ "allocating. Dropping allocated buffer.");
return;
}
@@ -1573,27 +1621,23 @@
};
#endif
- Vector<sp<GraphicBuffer>> buffers;
- for (size_t i = 0; i < newBufferCount; ++i) {
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)
- sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(allocRequest);
+ sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(allocRequest);
#else
- sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
- allocWidth, allocHeight, allocFormat, BQ_LAYER_COUNT,
- allocUsage, allocName);
+ sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
+ allocWidth, allocHeight, allocFormat, BQ_LAYER_COUNT,
+ allocUsage, allocName);
#endif
- status_t result = graphicBuffer->initCheck();
+ status_t result = graphicBuffer->initCheck();
- if (result != NO_ERROR) {
- BQ_LOGE("allocateBuffers: failed to allocate buffer (%u x %u, format"
- " %u, usage %#" PRIx64 ")", width, height, format, usage);
- std::lock_guard<std::mutex> lock(mCore->mMutex);
- mCore->mIsAllocating = false;
- mCore->mIsAllocatingCondition.notify_all();
- return;
- }
- buffers.push_back(graphicBuffer);
+ if (result != NO_ERROR) {
+ BQ_LOGE("allocateBuffers: failed to allocate buffer (%u x %u, format"
+ " %u, usage %#" PRIx64 ")", width, height, format, usage);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
+ mCore->mIsAllocating = false;
+ mCore->mIsAllocatingCondition.notify_all();
+ return;
}
{ // Autolock scope
@@ -1621,15 +1665,13 @@
continue;
}
- for (size_t i = 0; i < newBufferCount; ++i) {
- if (mCore->mFreeSlots.empty()) {
- BQ_LOGV("allocateBuffers: a slot was occupied while "
- "allocating. Dropping allocated buffer.");
- continue;
- }
+ if (mCore->mFreeSlots.empty()) {
+ BQ_LOGV("allocateBuffers: a slot was occupied while "
+ "allocating. Dropping allocated buffer.");
+ } else {
auto slot = mCore->mFreeSlots.begin();
mCore->clearBufferSlotLocked(*slot); // Clean up the slot first
- mSlots[*slot].mGraphicBuffer = buffers[i];
+ mSlots[*slot].mGraphicBuffer = graphicBuffer;
mSlots[*slot].mFence = Fence::NO_FENCE;
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)
mSlots[*slot].mAdditionalOptionsGenerationId = allocOptionsGenId;
diff --git a/libs/gui/BufferReleaseChannel.cpp b/libs/gui/BufferReleaseChannel.cpp
index 27367aa..e9c6ef3 100644
--- a/libs/gui/BufferReleaseChannel.cpp
+++ b/libs/gui/BufferReleaseChannel.cpp
@@ -136,6 +136,7 @@
status_t BufferReleaseChannel::ConsumerEndpoint::readReleaseFence(
ReleaseCallbackId& outReleaseCallbackId, sp<Fence>& outReleaseFence,
uint32_t& outMaxAcquiredBufferCount) {
+ std::lock_guard lock{mMutex};
Message message;
mFlattenedBuffer.resize(message.getFlattenedSize());
std::array<uint8_t, CMSG_SPACE(sizeof(int))> controlMessageBuffer;
@@ -152,7 +153,7 @@
.msg_controllen = controlMessageBuffer.size(),
};
- int result;
+ ssize_t result;
do {
result = recvmsg(mFd, &msg, 0);
} while (result == -1 && errno == EINTR);
@@ -242,7 +243,7 @@
memcpy(CMSG_DATA(cmsg), &flattenedFd, sizeof(int));
}
- int result;
+ ssize_t result;
do {
result = sendmsg(mFd, &msg, 0);
} while (result == -1 && errno == EINTR);
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 422c57b..4b53134 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -664,6 +664,10 @@
what |= eShadowRadiusChanged;
shadowRadius = other.shadowRadius;
}
+ if (other.what & eLutsChanged) {
+ what |= eLutsChanged;
+ luts = other.luts;
+ }
if (other.what & eDefaultFrameRateCompatibilityChanged) {
what |= eDefaultFrameRateCompatibilityChanged;
defaultFrameRateCompatibility = other.defaultFrameRateCompatibility;
@@ -821,6 +825,8 @@
CHECK_DIFF(diff, eColorSpaceAgnosticChanged, other, colorSpaceAgnostic);
CHECK_DIFF(diff, eDimmingEnabledChanged, other, dimmingEnabled);
if (other.what & eBufferReleaseChannelChanged) diff |= eBufferReleaseChannelChanged;
+ if (other.what & eLutsChanged) diff |= eLutsChanged;
+
return diff;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index eeea80f..a93fc92 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -29,6 +29,7 @@
#include <android/gui/IWindowInfosListener.h>
#include <android/gui/TrustedPresentationThresholds.h>
#include <android/os/IInputConstants.h>
+#include <gui/DisplayLuts.h>
#include <gui/FrameRateUtils.h>
#include <gui/TraceUtils.h>
#include <utils/Errors.h>
@@ -1940,15 +1941,19 @@
}
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLuts(
- const sp<SurfaceControl>& sc, const base::unique_fd& /*lutFd*/,
- const std::vector<int32_t>& /*offsets*/, const std::vector<int32_t>& /*dimensions*/,
- const std::vector<int32_t>& /*sizes*/, const std::vector<int32_t>& /*samplingKeys*/) {
+ const sp<SurfaceControl>& sc, const base::unique_fd& lutFd,
+ const std::vector<int32_t>& offsets, const std::vector<int32_t>& dimensions,
+ const std::vector<int32_t>& sizes, const std::vector<int32_t>& samplingKeys) {
layer_state_t* s = getLayerState(sc);
if (!s) {
mStatus = BAD_INDEX;
return *this;
}
- // TODO (b/329472856): update layer_state_t for lut(s)
+
+ s->luts = std::make_shared<gui::DisplayLuts>(base::unique_fd(dup(lutFd.get())), offsets,
+ dimensions, sizes, samplingKeys);
+ s->what |= layer_state_t::eLutsChanged;
+
registerSurfaceControlForCallback(sc);
return *this;
}
diff --git a/libs/gui/aidl/android/gui/Lut.aidl b/libs/gui/aidl/android/gui/Lut.aidl
deleted file mode 100644
index a06e521..0000000
--- a/libs/gui/aidl/android/gui/Lut.aidl
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2024 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.
- */
-
-package android.gui;
-
-import android.gui.LutProperties;
-import android.os.ParcelFileDescriptor;
-
-/**
- * This mirrors aidl::android::hardware::graphics::composer3::Lut definition
- * @hide
- */
-parcelable Lut {
- @nullable ParcelFileDescriptor pfd;
-
- LutProperties lutProperties;
-}
\ No newline at end of file
diff --git a/libs/gui/aidl/android/gui/LutProperties.aidl b/libs/gui/aidl/android/gui/LutProperties.aidl
index 561e0c0..87b878c 100644
--- a/libs/gui/aidl/android/gui/LutProperties.aidl
+++ b/libs/gui/aidl/android/gui/LutProperties.aidl
@@ -25,7 +25,7 @@
enum Dimension { ONE_D = 1, THREE_D = 3 }
Dimension dimension;
- long size;
+ int size;
@Backing(type="int")
enum SamplingKey { RGB, MAX_RGB }
SamplingKey[] samplingKeys;
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 8592cff..99c64da 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -150,6 +150,9 @@
private:
friend class BLASTBufferQueueHelper;
friend class BBQBufferQueueProducer;
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+ friend class BBQBufferQueueCore;
+#endif
// can't be copied
BLASTBufferQueue& operator = (const BLASTBufferQueue& rhs);
@@ -317,48 +320,52 @@
std::unordered_set<uint64_t> mSyncedFrameNumbers GUARDED_BY(mMutex);
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+ // BufferReleaseChannel is used to communicate buffer releases from SurfaceFlinger to the
+ // client.
+ std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint> mBufferReleaseConsumer;
+ std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> mBufferReleaseProducer;
+
class BufferReleaseReader {
public:
- BufferReleaseReader() = default;
- BufferReleaseReader(std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint>);
- BufferReleaseReader& operator=(BufferReleaseReader&&);
+ explicit BufferReleaseReader(BLASTBufferQueue&);
+
+ BufferReleaseReader(const BufferReleaseReader&) = delete;
+ BufferReleaseReader& operator=(const BufferReleaseReader&) = delete;
// Block until we can read a buffer release message.
//
// Returns:
// * OK if a ReleaseCallbackId and Fence were successfully read.
// * WOULD_BLOCK if the blocking read was interrupted by interruptBlockingRead.
+ // * TIMED_OUT if the blocking read timed out.
// * UNKNOWN_ERROR if something went wrong.
status_t readBlocking(ReleaseCallbackId& outId, sp<Fence>& outReleaseFence,
- uint32_t& outMaxAcquiredBufferCount);
+ uint32_t& outMaxAcquiredBufferCount, nsecs_t timeout);
- // Signals the reader's eventfd to wake up any threads waiting on readBlocking.
void interruptBlockingRead();
+ void clearInterrupts();
private:
- std::mutex mMutex;
- std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint> mEndpoint GUARDED_BY(mMutex);
+ BLASTBufferQueue& mBbq;
+
android::base::unique_fd mEpollFd;
android::base::unique_fd mEventFd;
};
- // BufferReleaseChannel is used to communicate buffer releases from SurfaceFlinger to
- // the client. See BBQBufferQueueProducer::dequeueBuffer for details.
- std::shared_ptr<BufferReleaseReader> mBufferReleaseReader;
- std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> mBufferReleaseProducer;
+ std::optional<BufferReleaseReader> mBufferReleaseReader;
+
+ std::atomic<int> mThreadsBlockingOnDequeue = 0;
class BufferReleaseThread {
public:
- BufferReleaseThread() = default;
+ BufferReleaseThread(const sp<BLASTBufferQueue>&);
~BufferReleaseThread();
- void start(const sp<BLASTBufferQueue>&);
private:
- std::shared_ptr<std::atomic_bool> mRunning;
- std::shared_ptr<BufferReleaseReader> mReader;
+ int mEventFd;
};
- BufferReleaseThread mBufferReleaseThread;
+ std::optional<BufferReleaseThread> mBufferReleaseThread;
#endif
};
diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h
index d5dd7c8..77cdf2c 100644
--- a/libs/gui/include/gui/BufferQueueCore.h
+++ b/libs/gui/include/gui/BufferQueueCore.h
@@ -80,6 +80,13 @@
BufferQueueCore();
virtual ~BufferQueueCore();
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+protected:
+ // Wake up any threads waiting for a buffer release. The BufferQueue mutex should always held
+ // when this method is called.
+ virtual void notifyBufferReleased() const;
+#endif
+
private:
// Dump our state in a string
void dumpState(const String8& prefix, String8* outResult) const;
diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h
index 37a9607..086ce7c 100644
--- a/libs/gui/include/gui/BufferQueueProducer.h
+++ b/libs/gui/include/gui/BufferQueueProducer.h
@@ -218,6 +218,14 @@
// total maximum buffer count for the buffer queue (dequeued AND acquired)
status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers, int* maxBufferCount);
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+ // Wait until a buffer has been released. The method may spuriously return OK when no buffer has
+ // been released. The BufferQueue mutex is passed in the locked state. It must be unlocked
+ // before waiting for a release and locked before returning.
+ virtual status_t waitForBufferRelease(std::unique_lock<std::mutex>& lock,
+ nsecs_t timeout) const;
+#endif
+
private:
// This is required by the IBinder::DeathRecipient interface
virtual void binderDied(const wp<IBinder>& who);
diff --git a/libs/gui/include/gui/BufferReleaseChannel.h b/libs/gui/include/gui/BufferReleaseChannel.h
index 51fe0b6..0edadec 100644
--- a/libs/gui/include/gui/BufferReleaseChannel.h
+++ b/libs/gui/include/gui/BufferReleaseChannel.h
@@ -69,7 +69,8 @@
sp<Fence>& outReleaseFence, uint32_t& maxAcquiredBufferCount);
private:
- std::vector<uint8_t> mFlattenedBuffer;
+ std::mutex mMutex;
+ std::vector<uint8_t> mFlattenedBuffer GUARDED_BY(mMutex);
};
class ProducerEndpoint : public Endpoint, public Parcelable {
diff --git a/libs/gui/include/gui/DisplayLuts.h b/libs/gui/include/gui/DisplayLuts.h
new file mode 100644
index 0000000..16a360d
--- /dev/null
+++ b/libs/gui/include/gui/DisplayLuts.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2024 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 <android-base/unique_fd.h>
+#include <vector>
+
+namespace android::gui {
+
+struct DisplayLuts {
+public:
+ struct Entry {
+ int32_t dimension;
+ int32_t size;
+ int32_t samplingKey;
+ };
+
+ DisplayLuts() {}
+
+ DisplayLuts(base::unique_fd lutfd, std::vector<int32_t> lutoffsets,
+ std::vector<int32_t> lutdimensions, std::vector<int32_t> lutsizes,
+ std::vector<int32_t> lutsamplingKeys) {
+ fd = std::move(lutfd);
+ offsets = lutoffsets;
+ lutProperties.reserve(offsets.size());
+ for (size_t i = 0; i < lutoffsets.size(); i++) {
+ Entry entry{lutdimensions[i], lutsizes[i], lutsamplingKeys[i]};
+ lutProperties.emplace_back(entry);
+ }
+ }
+
+ base::unique_fd& getLutFileDescriptor() { return fd; }
+
+ std::vector<Entry> lutProperties;
+ std::vector<int32_t> offsets;
+
+private:
+ base::unique_fd fd;
+}; // struct DisplayLuts
+
+} // namespace android::gui
\ No newline at end of file
diff --git a/libs/gui/include/gui/Flags.h b/libs/gui/include/gui/Flags.h
index 735375a..34350d2 100644
--- a/libs/gui/include/gui/Flags.h
+++ b/libs/gui/include/gui/Flags.h
@@ -17,8 +17,20 @@
#pragma once
#include <com_android_graphics_libgui_flags.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/Surface.h>
#define WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES \
(COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CAMERA3_AND_PROCESSORS) && \
COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) && \
- COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS))
\ No newline at end of file
+ COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS))
+
+#define WB_LIBCAMERASERVICE_WITH_DEPENDENCIES \
+ (WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES && \
+ COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_LIBCAMERASERVICE))
+
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+typedef android::Surface SurfaceType;
+#else
+typedef android::IGraphicBufferProducer SurfaceType;
+#endif
\ No newline at end of file
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 00065c8..6bfeaec 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -26,6 +26,7 @@
#include <android/gui/LayerCaptureArgs.h>
#include <android/gui/TrustedPresentationThresholds.h>
#include <android/native_window.h>
+#include <gui/DisplayLuts.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/ITransactionCompletedListener.h>
#include <math/mat4.h>
@@ -184,6 +185,7 @@
eCachingHintChanged = 0x00000200,
eDimmingEnabledChanged = 0x00000400,
eShadowRadiusChanged = 0x00000800,
+ eLutsChanged = 0x00001000,
eBufferCropChanged = 0x00002000,
eRelativeLayerChanged = 0x00004000,
eReparent = 0x00008000,
@@ -255,7 +257,7 @@
layer_state_t::eTransformToDisplayInverseChanged |
layer_state_t::eTransparentRegionChanged |
layer_state_t::eExtendedRangeBrightnessChanged |
- layer_state_t::eDesiredHdrHeadroomChanged;
+ layer_state_t::eDesiredHdrHeadroomChanged | layer_state_t::eLutsChanged;
// Content updates.
static constexpr uint64_t CONTENT_CHANGES = layer_state_t::BUFFER_CHANGES |
@@ -416,6 +418,8 @@
TrustedPresentationListener trustedPresentationListener;
std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> bufferReleaseChannel;
+
+ std::shared_ptr<gui::DisplayLuts> luts;
};
class ComposerState {
diff --git a/libs/gui/include/gui/view/Surface.h b/libs/gui/include/gui/view/Surface.h
index 7ddac81..7c762d3 100644
--- a/libs/gui/include/gui/view/Surface.h
+++ b/libs/gui/include/gui/view/Surface.h
@@ -24,7 +24,9 @@
#include <binder/IBinder.h>
#include <binder/Parcelable.h>
+#include <gui/Flags.h>
#include <gui/IGraphicBufferProducer.h>
+#include <gui/Surface.h>
namespace android {
@@ -46,6 +48,14 @@
sp<IGraphicBufferProducer> graphicBufferProducer;
sp<IBinder> surfaceControlHandle;
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+ // functions used to convert to a parcelable Surface so it can be passed over binder.
+ static Surface fromSurface(const sp<android::Surface>& surface);
+ sp<android::Surface> toSurface() const;
+
+ status_t getUniqueId(/* out */ uint64_t* id) const;
+#endif
+
virtual status_t writeToParcel(Parcel* parcel) const override;
virtual status_t readFromParcel(const Parcel* parcel) override;
diff --git a/libs/gui/tests/BufferItemConsumer_test.cpp b/libs/gui/tests/BufferItemConsumer_test.cpp
index 845a1ca..3b6a66e 100644
--- a/libs/gui/tests/BufferItemConsumer_test.cpp
+++ b/libs/gui/tests/BufferItemConsumer_test.cpp
@@ -30,6 +30,7 @@
static constexpr int kHeight = 100;
static constexpr int kMaxLockedBuffers = 3;
static constexpr int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+static constexpr int kUsage = GRALLOC_USAGE_SW_READ_RARELY;
static constexpr int kFrameSleepUs = 30 * 1000;
class BufferItemConsumerTest : public ::testing::Test {
@@ -56,7 +57,7 @@
};
void SetUp() override {
- mBIC = new BufferItemConsumer(kFormat, kMaxLockedBuffers, true);
+ mBIC = new BufferItemConsumer(kUsage, kMaxLockedBuffers, true);
String8 name("BufferItemConsumer_Under_Test");
mBIC->setName(name);
mBFL = new BufferFreedListener(this);
diff --git a/libs/gui/view/Surface.cpp b/libs/gui/view/Surface.cpp
index 84c2a6a..9f57923 100644
--- a/libs/gui/view/Surface.cpp
+++ b/libs/gui/view/Surface.cpp
@@ -121,6 +121,38 @@
return str.value_or(String16());
}
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+Surface Surface::fromSurface(const sp<android::Surface>& surface) {
+ if (surface == nullptr) {
+ ALOGE("%s: Error: view::Surface::fromSurface failed due to null surface.", __FUNCTION__);
+ return Surface();
+ }
+ Surface s;
+ s.name = String16(surface->getConsumerName());
+ s.graphicBufferProducer = surface->getIGraphicBufferProducer();
+ s.surfaceControlHandle = surface->getSurfaceControlHandle();
+ return s;
+}
+
+sp<android::Surface> Surface::toSurface() const {
+ if (graphicBufferProducer == nullptr) return nullptr;
+ return new android::Surface(graphicBufferProducer, false, surfaceControlHandle);
+}
+
+status_t Surface::getUniqueId(uint64_t* out_id) const {
+ if (graphicBufferProducer == nullptr) {
+ ALOGE("android::viewSurface::getUniqueId() failed because it's not initialized.");
+ return UNEXPECTED_NULL;
+ }
+ status_t status = graphicBufferProducer->getUniqueId(out_id);
+ if (status != OK) {
+ ALOGE("android::viewSurface::getUniqueId() failed.");
+ return status;
+ }
+ return OK;
+}
+#endif
+
std::string Surface::toString() const {
std::stringstream out;
out << name;
diff --git a/libs/input/InputConsumerNoResampling.cpp b/libs/input/InputConsumerNoResampling.cpp
index 9665de7..d3653cf 100644
--- a/libs/input/InputConsumerNoResampling.cpp
+++ b/libs/input/InputConsumerNoResampling.cpp
@@ -357,7 +357,8 @@
mBatches[deviceId].emplace(msg);
} else {
// consume all pending batches for this device immediately
- consumeBatchedInputEvents(deviceId, /*requestedFrameTime=*/std::nullopt);
+ consumeBatchedInputEvents(deviceId, /*requestedFrameTime=*/
+ std::numeric_limits<nsecs_t>::max());
if (canResample &&
(action == AMOTION_EVENT_ACTION_UP || action == AMOTION_EVENT_ACTION_CANCEL)) {
LOG_IF(INFO, mResamplers.erase(deviceId) == 0)
@@ -480,7 +481,7 @@
}
std::pair<std::unique_ptr<MotionEvent>, std::optional<uint32_t>>
-InputConsumerNoResampling::createBatchedMotionEvent(const nsecs_t requestedFrameTime,
+InputConsumerNoResampling::createBatchedMotionEvent(const std::optional<nsecs_t> requestedFrameTime,
std::queue<InputMessage>& messages) {
std::unique_ptr<MotionEvent> motionEvent;
std::optional<uint32_t> firstSeqForBatch;
@@ -491,7 +492,11 @@
const nanoseconds resampleLatency = (resampler != mResamplers.cend())
? resampler->second->getResampleLatency()
: nanoseconds{0};
- const nanoseconds adjustedFrameTime = nanoseconds{requestedFrameTime} - resampleLatency;
+ // When batching is not enabled, we want to consume all events. That's equivalent to having an
+ // infinite requestedFrameTime.
+ const nanoseconds adjustedFrameTime = (requestedFrameTime.has_value())
+ ? (nanoseconds{*requestedFrameTime} - resampleLatency)
+ : nanoseconds{std::numeric_limits<nsecs_t>::max()};
while (!messages.empty() &&
(messages.front().body.motion.eventTime <= adjustedFrameTime.count())) {
@@ -513,8 +518,9 @@
if (!messages.empty()) {
futureSample = &messages.front();
}
- if ((motionEvent != nullptr) && (resampler != mResamplers.cend())) {
- resampler->second->resampleMotionEvent(nanoseconds{requestedFrameTime}, *motionEvent,
+ if ((motionEvent != nullptr) && (resampler != mResamplers.cend()) &&
+ (requestedFrameTime.has_value())) {
+ resampler->second->resampleMotionEvent(nanoseconds{*requestedFrameTime}, *motionEvent,
futureSample);
}
@@ -524,16 +530,13 @@
bool InputConsumerNoResampling::consumeBatchedInputEvents(
std::optional<DeviceId> deviceId, std::optional<nsecs_t> requestedFrameTime) {
ensureCalledOnLooperThread(__func__);
- // When batching is not enabled, we want to consume all events. That's equivalent to having an
- // infinite requestedFrameTime.
- requestedFrameTime = requestedFrameTime.value_or(std::numeric_limits<nsecs_t>::max());
bool producedEvents = false;
for (auto deviceIdIter = (deviceId.has_value()) ? (mBatches.find(*deviceId))
: (mBatches.begin());
deviceIdIter != mBatches.cend(); ++deviceIdIter) {
std::queue<InputMessage>& messages = deviceIdIter->second;
- auto [motion, firstSeqForBatch] = createBatchedMotionEvent(*requestedFrameTime, messages);
+ auto [motion, firstSeqForBatch] = createBatchedMotionEvent(requestedFrameTime, messages);
if (motion != nullptr) {
LOG_ALWAYS_FATAL_IF(!firstSeqForBatch.has_value());
mCallbacks.onMotionEvent(std::move(motion), *firstSeqForBatch);
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index c903031..4a6f66e 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -191,7 +191,9 @@
mKeyboardLayoutInfo(other.mKeyboardLayoutInfo),
mSources(other.mSources),
mKeyboardType(other.mKeyboardType),
- mKeyCharacterMap(other.mKeyCharacterMap),
+ mKeyCharacterMap(other.mKeyCharacterMap
+ ? std::make_unique<KeyCharacterMap>(*other.mKeyCharacterMap)
+ : nullptr),
mUsiVersion(other.mUsiVersion),
mAssociatedDisplayId(other.mAssociatedDisplayId),
mEnabled(other.mEnabled),
@@ -204,6 +206,34 @@
mLights(other.mLights),
mViewBehavior(other.mViewBehavior) {}
+InputDeviceInfo& InputDeviceInfo::operator=(const InputDeviceInfo& other) {
+ mId = other.mId;
+ mGeneration = other.mGeneration;
+ mControllerNumber = other.mControllerNumber;
+ mIdentifier = other.mIdentifier;
+ mAlias = other.mAlias;
+ mIsExternal = other.mIsExternal;
+ mHasMic = other.mHasMic;
+ mKeyboardLayoutInfo = other.mKeyboardLayoutInfo;
+ mSources = other.mSources;
+ mKeyboardType = other.mKeyboardType;
+ mKeyCharacterMap = other.mKeyCharacterMap
+ ? std::make_unique<KeyCharacterMap>(*other.mKeyCharacterMap)
+ : nullptr;
+ mUsiVersion = other.mUsiVersion;
+ mAssociatedDisplayId = other.mAssociatedDisplayId;
+ mEnabled = other.mEnabled;
+ mHasVibrator = other.mHasVibrator;
+ mHasBattery = other.mHasBattery;
+ mHasButtonUnderPad = other.mHasButtonUnderPad;
+ mHasSensor = other.mHasSensor;
+ mMotionRanges = other.mMotionRanges;
+ mSensors = other.mSensors;
+ mLights = other.mLights;
+ mViewBehavior = other.mViewBehavior;
+ return *this;
+}
+
InputDeviceInfo::~InputDeviceInfo() {
}
diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp
index d775327..90d29dd 100644
--- a/libs/input/KeyCharacterMap.cpp
+++ b/libs/input/KeyCharacterMap.cpp
@@ -84,15 +84,15 @@
KeyCharacterMap::KeyCharacterMap(const std::string& filename) : mLoadFileName(filename) {}
-base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::load(const std::string& filename,
+base::Result<std::unique_ptr<KeyCharacterMap>> KeyCharacterMap::load(const std::string& filename,
Format format) {
Tokenizer* tokenizer;
status_t status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
if (status) {
return Errorf("Error {} opening key character map file {}.", status, filename.c_str());
}
- std::shared_ptr<KeyCharacterMap> map =
- std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(filename));
+ std::unique_ptr<KeyCharacterMap> map =
+ std::unique_ptr<KeyCharacterMap>(new KeyCharacterMap(filename));
if (!map.get()) {
ALOGE("Error allocating key character map.");
return Errorf("Error allocating key character map.");
diff --git a/libs/input/Resampler.cpp b/libs/input/Resampler.cpp
index e2cc6fb..056db09 100644
--- a/libs/input/Resampler.cpp
+++ b/libs/input/Resampler.cpp
@@ -18,6 +18,7 @@
#include <algorithm>
#include <chrono>
+#include <iomanip>
#include <ostream>
#include <android-base/logging.h>
@@ -37,6 +38,11 @@
true;
#endif
+/**
+ * Log debug messages about timestamp and coordinates of event resampling.
+ * Enable this via "adb shell setprop log.tag.LegacyResamplerResampling DEBUG"
+ * (requires restart)
+ */
bool debugResampling() {
if (!IS_DEBUGGABLE_BUILD) {
static const bool DEBUG_TRANSPORT_RESAMPLING =
@@ -107,46 +113,44 @@
const size_t latestIndex = numSamples - 1;
const size_t secondToLatestIndex = (latestIndex > 0) ? (latestIndex - 1) : 0;
for (size_t sampleIndex = secondToLatestIndex; sampleIndex < numSamples; ++sampleIndex) {
- std::vector<Pointer> pointers;
- const size_t numPointers = motionEvent.getPointerCount();
- for (size_t pointerIndex = 0; pointerIndex < numPointers; ++pointerIndex) {
- pointers.push_back(Pointer{*(motionEvent.getPointerProperties(pointerIndex)),
- *(motionEvent.getHistoricalRawPointerCoords(pointerIndex,
- sampleIndex))});
+ PointerMap pointerMap;
+ for (size_t pointerIndex = 0; pointerIndex < motionEvent.getPointerCount();
+ ++pointerIndex) {
+ pointerMap.insert(Pointer{*(motionEvent.getPointerProperties(pointerIndex)),
+ *(motionEvent.getHistoricalRawPointerCoords(pointerIndex,
+ sampleIndex))});
}
mLatestSamples.pushBack(
- Sample{nanoseconds{motionEvent.getHistoricalEventTime(sampleIndex)}, pointers});
+ Sample{nanoseconds{motionEvent.getHistoricalEventTime(sampleIndex)}, pointerMap});
}
}
LegacyResampler::Sample LegacyResampler::messageToSample(const InputMessage& message) {
- std::vector<Pointer> pointers;
+ PointerMap pointerMap;
for (uint32_t i = 0; i < message.body.motion.pointerCount; ++i) {
- pointers.push_back(Pointer{message.body.motion.pointers[i].properties,
- message.body.motion.pointers[i].coords});
+ pointerMap.insert(Pointer{message.body.motion.pointers[i].properties,
+ message.body.motion.pointers[i].coords});
}
- return Sample{nanoseconds{message.body.motion.eventTime}, pointers};
+ return Sample{nanoseconds{message.body.motion.eventTime}, pointerMap};
}
bool LegacyResampler::pointerPropertiesResampleable(const Sample& target, const Sample& auxiliary) {
- if (target.pointers.size() > auxiliary.pointers.size()) {
- LOG_IF(INFO, debugResampling())
- << "Not resampled. Auxiliary sample has fewer pointers than target sample.";
- return false;
- }
- for (size_t i = 0; i < target.pointers.size(); ++i) {
- if (target.pointers[i].properties.id != auxiliary.pointers[i].properties.id) {
- LOG_IF(INFO, debugResampling()) << "Not resampled. Pointer ID mismatch.";
+ for (const Pointer& pointer : target.pointerMap) {
+ const std::optional<Pointer> auxiliaryPointer =
+ auxiliary.pointerMap.find(PointerMap::PointerId{pointer.properties.id});
+ if (!auxiliaryPointer.has_value()) {
+ LOG_IF(INFO, debugResampling())
+ << "Not resampled. Auxiliary sample does not contain all pointers from target.";
return false;
}
- if (target.pointers[i].properties.toolType != auxiliary.pointers[i].properties.toolType) {
+ if (pointer.properties.toolType != auxiliaryPointer->properties.toolType) {
LOG_IF(INFO, debugResampling()) << "Not resampled. Pointer ToolType mismatch.";
return false;
}
- if (!canResampleTool(target.pointers[i].properties.toolType)) {
+ if (!canResampleTool(pointer.properties.toolType)) {
LOG_IF(INFO, debugResampling())
<< "Not resampled. Cannot resample "
- << ftl::enum_string(target.pointers[i].properties.toolType) << " ToolType.";
+ << ftl::enum_string(pointer.properties.toolType) << " ToolType.";
return false;
}
}
@@ -166,35 +170,40 @@
const nanoseconds delta = futureSample.eventTime - pastSample.eventTime;
if (delta < RESAMPLE_MIN_DELTA) {
- LOG_IF(INFO, debugResampling()) << "Not resampled. Delta is too small: " << delta << "ns.";
+ LOG_IF(INFO, debugResampling())
+ << "Not resampled. Delta is too small: " << std::setprecision(3)
+ << std::chrono::duration<double, std::milli>{delta}.count() << "ms";
return false;
}
return true;
}
std::optional<LegacyResampler::Sample> LegacyResampler::attemptInterpolation(
- nanoseconds resampleTime, const InputMessage& futureSample) const {
- if (!canInterpolate(futureSample)) {
+ nanoseconds resampleTime, const InputMessage& futureMessage) const {
+ if (!canInterpolate(futureMessage)) {
return std::nullopt;
}
LOG_IF(FATAL, mLatestSamples.empty())
<< "Not resampled. mLatestSamples must not be empty to interpolate.";
const Sample& pastSample = *(mLatestSamples.end() - 1);
+ const Sample& futureSample = messageToSample(futureMessage);
- const nanoseconds delta =
- nanoseconds{futureSample.body.motion.eventTime} - pastSample.eventTime;
+ const nanoseconds delta = nanoseconds{futureSample.eventTime} - pastSample.eventTime;
const float alpha =
- std::chrono::duration<float, std::milli>(resampleTime - pastSample.eventTime) / delta;
+ std::chrono::duration<float, std::nano>(resampleTime - pastSample.eventTime) / delta;
- std::vector<Pointer> resampledPointers;
- for (size_t i = 0; i < pastSample.pointers.size(); ++i) {
- const PointerCoords& resampledCoords =
- calculateResampledCoords(pastSample.pointers[i].coords,
- futureSample.body.motion.pointers[i].coords, alpha);
- resampledPointers.push_back(Pointer{pastSample.pointers[i].properties, resampledCoords});
+ PointerMap resampledPointerMap;
+ for (const Pointer& pointer : pastSample.pointerMap) {
+ if (std::optional<Pointer> futureSamplePointer =
+ futureSample.pointerMap.find(PointerMap::PointerId{pointer.properties.id});
+ futureSamplePointer.has_value()) {
+ const PointerCoords& resampledCoords =
+ calculateResampledCoords(pointer.coords, futureSamplePointer->coords, alpha);
+ resampledPointerMap.insert(Pointer{pointer.properties, resampledCoords});
+ }
}
- return Sample{resampleTime, resampledPointers};
+ return Sample{resampleTime, resampledPointerMap};
}
bool LegacyResampler::canExtrapolate() const {
@@ -212,10 +221,14 @@
const nanoseconds delta = presentSample.eventTime - pastSample.eventTime;
if (delta < RESAMPLE_MIN_DELTA) {
- LOG_IF(INFO, debugResampling()) << "Not resampled. Delta is too small: " << delta << "ns.";
+ LOG_IF(INFO, debugResampling())
+ << "Not resampled. Delta is too small: " << std::setprecision(3)
+ << std::chrono::duration<double, std::milli>{delta}.count() << "ms";
return false;
} else if (delta > RESAMPLE_MAX_DELTA) {
- LOG_IF(INFO, debugResampling()) << "Not resampled. Delta is too large: " << delta << "ns.";
+ LOG_IF(INFO, debugResampling())
+ << "Not resampled. Delta is too large: " << std::setprecision(3)
+ << std::chrono::duration<double, std::milli>{delta}.count() << "ms";
return false;
}
return true;
@@ -241,20 +254,28 @@
(resampleTime > farthestPrediction) ? (farthestPrediction) : (resampleTime);
LOG_IF(INFO, debugResampling() && newResampleTime == farthestPrediction)
<< "Resample time is too far in the future. Adjusting prediction from "
- << (resampleTime - presentSample.eventTime) << " to "
- << (farthestPrediction - presentSample.eventTime) << "ns.";
+ << std::setprecision(3)
+ << std::chrono::duration<double, std::milli>{resampleTime - presentSample.eventTime}
+ .count()
+ << "ms to "
+ << std::chrono::duration<double, std::milli>{farthestPrediction -
+ presentSample.eventTime}
+ .count()
+ << "ms";
const float alpha =
- std::chrono::duration<float, std::milli>(newResampleTime - pastSample.eventTime) /
- delta;
+ std::chrono::duration<float, std::nano>(newResampleTime - pastSample.eventTime) / delta;
- std::vector<Pointer> resampledPointers;
- for (size_t i = 0; i < presentSample.pointers.size(); ++i) {
- const PointerCoords& resampledCoords =
- calculateResampledCoords(pastSample.pointers[i].coords,
- presentSample.pointers[i].coords, alpha);
- resampledPointers.push_back(Pointer{presentSample.pointers[i].properties, resampledCoords});
+ PointerMap resampledPointerMap;
+ for (const Pointer& pointer : presentSample.pointerMap) {
+ if (std::optional<Pointer> pastSamplePointer =
+ pastSample.pointerMap.find(PointerMap::PointerId{pointer.properties.id});
+ pastSamplePointer.has_value()) {
+ const PointerCoords& resampledCoords =
+ calculateResampledCoords(pastSamplePointer->coords, pointer.coords, alpha);
+ resampledPointerMap.insert(Pointer{pointer.properties, resampledCoords});
+ }
}
- return Sample{newResampleTime, resampledPointers};
+ return Sample{newResampleTime, resampledPointerMap};
}
inline void LegacyResampler::addSampleToMotionEvent(const Sample& sample,
@@ -267,6 +288,12 @@
return RESAMPLE_LATENCY;
}
+/**
+ * The resampler is unaware of ACTION_DOWN. Thus, it needs to constantly check for pointer IDs
+ * occurrences. This problem could be fixed if the resampler has access to the entire stream of
+ * MotionEvent actions. That way, both ACTION_DOWN and ACTION_UP will be visible; therefore,
+ * facilitating pointer tracking between samples.
+ */
void LegacyResampler::overwriteMotionEventSamples(MotionEvent& motionEvent) const {
const size_t numSamples = motionEvent.getHistorySize() + 1;
for (size_t sampleIndex = 0; sampleIndex < numSamples; ++sampleIndex) {
@@ -276,34 +303,59 @@
}
void LegacyResampler::overwriteStillPointers(MotionEvent& motionEvent, size_t sampleIndex) const {
+ if (!mLastRealSample.has_value() || !mPreviousPrediction.has_value()) {
+ LOG_IF(INFO, debugResampling()) << "Still pointers not overwritten. Not enough data.";
+ return;
+ }
for (size_t pointerIndex = 0; pointerIndex < motionEvent.getPointerCount(); ++pointerIndex) {
+ const std::optional<Pointer> lastRealPointer = mLastRealSample->pointerMap.find(
+ PointerMap::PointerId{motionEvent.getPointerId(pointerIndex)});
+ const std::optional<Pointer> previousPointer = mPreviousPrediction->pointerMap.find(
+ PointerMap::PointerId{motionEvent.getPointerId(pointerIndex)});
+ // This could happen because resampler only receives ACTION_MOVE events.
+ if (!lastRealPointer.has_value() || !previousPointer.has_value()) {
+ continue;
+ }
const PointerCoords& pointerCoords =
*(motionEvent.getHistoricalRawPointerCoords(pointerIndex, sampleIndex));
- if (equalXY(mLastRealSample->pointers[pointerIndex].coords, pointerCoords)) {
+ if (equalXY(pointerCoords, lastRealPointer->coords)) {
LOG_IF(INFO, debugResampling())
<< "Pointer ID: " << motionEvent.getPointerId(pointerIndex)
<< " did not move. Overwriting its coordinates from " << pointerCoords << " to "
- << mLastRealSample->pointers[pointerIndex].coords;
+ << previousPointer->coords;
setMotionEventPointerCoords(motionEvent, sampleIndex, pointerIndex,
- mPreviousPrediction->pointers[pointerIndex].coords);
+ previousPointer->coords);
}
}
}
void LegacyResampler::overwriteOldPointers(MotionEvent& motionEvent, size_t sampleIndex) const {
if (!mPreviousPrediction.has_value()) {
+ LOG_IF(INFO, debugResampling()) << "Old sample not overwritten. Not enough data.";
return;
}
if (nanoseconds{motionEvent.getHistoricalEventTime(sampleIndex)} <
mPreviousPrediction->eventTime) {
LOG_IF(INFO, debugResampling())
<< "Motion event sample older than predicted sample. Overwriting event time from "
- << motionEvent.getHistoricalEventTime(sampleIndex) << "ns to "
- << mPreviousPrediction->eventTime.count() << "ns.";
+ << std::setprecision(3)
+ << std::chrono::duration<double,
+ std::milli>{nanoseconds{motionEvent.getHistoricalEventTime(
+ sampleIndex)}}
+ .count()
+ << "ms to "
+ << std::chrono::duration<double, std::milli>{mPreviousPrediction->eventTime}.count()
+ << "ms";
for (size_t pointerIndex = 0; pointerIndex < motionEvent.getPointerCount();
++pointerIndex) {
+ const std::optional<Pointer> previousPointer = mPreviousPrediction->pointerMap.find(
+ PointerMap::PointerId{motionEvent.getPointerId(pointerIndex)});
+ // This could happen because resampler only receives ACTION_MOVE events.
+ if (!previousPointer.has_value()) {
+ continue;
+ }
setMotionEventPointerCoords(motionEvent, sampleIndex, pointerIndex,
- mPreviousPrediction->pointers[pointerIndex].coords);
+ previousPointer->coords);
}
}
}
@@ -333,6 +385,7 @@
mPreviousPrediction = sample;
}
}
+ LOG_IF(FATAL, mLatestSamples.empty()) << "mLatestSamples must contain at least one sample.";
mLastRealSample = *(mLatestSamples.end() - 1);
}
diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig
index 701fb43..484a5df 100644
--- a/libs/input/input_flags.aconfig
+++ b/libs/input/input_flags.aconfig
@@ -94,13 +94,6 @@
}
flag {
- name: "enable_new_mouse_pointer_ballistics"
- namespace: "input"
- description: "Change the acceleration curves for mouse pointer movements to match the touchpad ones"
- bug: "315313622"
-}
-
-flag {
name: "rate_limit_user_activity_poke_in_dispatcher"
namespace: "input"
description: "Move user-activity poke rate-limiting from PowerManagerService to InputDispatcher."
@@ -214,3 +207,20 @@
description: "Enable telemetry for rotary input"
bug: "370353565"
}
+
+flag {
+ name: "set_input_device_kernel_wake"
+ namespace: "input"
+ description: "Set input device's power/wakeup sysfs node"
+ bug: "372812925"
+}
+
+flag {
+ name: "enable_alphabetic_keyboard_wake"
+ namespace: "input"
+ description: "Enable wake from alphabetic keyboards."
+ bug: "352856881"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/libs/input/tests/InputConsumerResampling_test.cpp b/libs/input/tests/InputConsumerResampling_test.cpp
index 883ca82..97688a8 100644
--- a/libs/input/tests/InputConsumerResampling_test.cpp
+++ b/libs/input/tests/InputConsumerResampling_test.cpp
@@ -38,6 +38,8 @@
using std::chrono::nanoseconds;
using namespace std::chrono_literals;
+const std::chrono::milliseconds RESAMPLE_LATENCY{5};
+
struct Pointer {
int32_t id{0};
float x{0.0f};
@@ -440,7 +442,7 @@
{20ms, {Pointer{.id = 0, .x = 30.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE}));
invokeLooperCallback();
- mConsumer->consumeBatchedInputEvents(nanoseconds{20ms + 5ms /*RESAMPLE_LATENCY*/}.count());
+ mConsumer->consumeBatchedInputEvents(nanoseconds{20ms + RESAMPLE_LATENCY}.count());
// MotionEvent should not resampled because the resample time falls exactly on the existing
// event time.
@@ -496,14 +498,15 @@
{40ms, {Pointer{.id = 0, .x = 30.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE}));
invokeLooperCallback();
- mConsumer->consumeBatchedInputEvents(nanoseconds{45ms + 5ms /*RESAMPLE_LATENCY*/}.count());
+ mConsumer->consumeBatchedInputEvents(nanoseconds{45ms + RESAMPLE_LATENCY}.count());
+ // Original and resampled event should be both overwritten.
assertReceivedMotionEvent(
{InputEventEntry{40ms,
{Pointer{.id = 0, .x = 35.0f, .y = 30.0f, .isResampled = true}},
- AMOTION_EVENT_ACTION_MOVE}, // original event, rewritten
+ AMOTION_EVENT_ACTION_MOVE},
InputEventEntry{45ms,
{Pointer{.id = 0, .x = 35.0f, .y = 30.0f, .isResampled = true}},
- AMOTION_EVENT_ACTION_MOVE}}); // resampled event, rewritten
+ AMOTION_EVENT_ACTION_MOVE}});
mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true);
mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true);
@@ -552,13 +555,14 @@
invokeLooperCallback();
mConsumer->consumeBatchedInputEvents(nanoseconds{50ms}.count());
+ // Original and resampled event should be both overwritten.
assertReceivedMotionEvent(
{InputEventEntry{24ms,
{Pointer{.id = 0, .x = 35.0f, .y = 30.0f, .isResampled = true}},
- AMOTION_EVENT_ACTION_MOVE}, // original event, rewritten
+ AMOTION_EVENT_ACTION_MOVE},
InputEventEntry{26ms,
{Pointer{.id = 0, .x = 45.0f, .y = 30.0f, .isResampled = true}},
- AMOTION_EVENT_ACTION_MOVE}}); // resampled event, rewritten
+ AMOTION_EVENT_ACTION_MOVE}});
mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true);
mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true);
@@ -566,4 +570,175 @@
mClientTestChannel->assertFinishMessage(/*seq=*/4, /*handled=*/true);
}
+TEST_F(InputConsumerResamplingTest, DoNotResampleWhenFrameTimeIsNotAvailable) {
+ mClientTestChannel->enqueueMessage(nextPointerMessage(
+ {0ms, {Pointer{.id = 0, .x = 10.0f, .y = 20.0f}}, AMOTION_EVENT_ACTION_DOWN}));
+
+ invokeLooperCallback();
+ assertReceivedMotionEvent({InputEventEntry{0ms,
+ {Pointer{.id = 0, .x = 10.0f, .y = 20.0f}},
+ AMOTION_EVENT_ACTION_DOWN}});
+
+ mClientTestChannel->enqueueMessage(nextPointerMessage(
+ {10ms, {Pointer{.id = 0, .x = 20.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE}));
+ mClientTestChannel->enqueueMessage(nextPointerMessage(
+ {20ms, {Pointer{.id = 0, .x = 30.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE}));
+
+ invokeLooperCallback();
+ mConsumer->consumeBatchedInputEvents(std::nullopt);
+ assertReceivedMotionEvent({InputEventEntry{10ms,
+ {Pointer{.id = 0, .x = 20.0f, .y = 30.0f}},
+ AMOTION_EVENT_ACTION_MOVE},
+ InputEventEntry{20ms,
+ {Pointer{.id = 0, .x = 30.0f, .y = 30.0f}},
+ AMOTION_EVENT_ACTION_MOVE}});
+
+ mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true);
+ mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true);
+ mClientTestChannel->assertFinishMessage(/*seq=*/3, /*handled=*/true);
+}
+
+TEST_F(InputConsumerResamplingTest, TwoPointersAreResampledIndependently) {
+ // Full action for when a pointer with index=1 appears (some other pointer must already be
+ // present)
+ const int32_t actionPointer1Down =
+ AMOTION_EVENT_ACTION_POINTER_DOWN + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+
+ // Full action for when a pointer with index=0 disappears (some other pointer must still remain)
+ const int32_t actionPointer0Up =
+ AMOTION_EVENT_ACTION_POINTER_UP + (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+
+ mClientTestChannel->enqueueMessage(nextPointerMessage(
+ {0ms, {Pointer{.id = 0, .x = 100.0f, .y = 100.0f}}, AMOTION_EVENT_ACTION_DOWN}));
+
+ mClientTestChannel->assertNoSentMessages();
+
+ invokeLooperCallback();
+ assertReceivedMotionEvent({InputEventEntry{0ms,
+ {Pointer{.id = 0, .x = 100.0f, .y = 100.0f}},
+ AMOTION_EVENT_ACTION_DOWN}});
+
+ mClientTestChannel->enqueueMessage(nextPointerMessage(
+ {10ms, {Pointer{.id = 0, .x = 100.0f, .y = 100.0f}}, AMOTION_EVENT_ACTION_MOVE}));
+
+ invokeLooperCallback();
+ mConsumer->consumeBatchedInputEvents(nanoseconds{10ms + RESAMPLE_LATENCY}.count());
+ // Not resampled value because requestedFrameTime - RESAMPLE_LATENCY == eventTime
+ assertReceivedMotionEvent({InputEventEntry{10ms,
+ {Pointer{.id = 0, .x = 100.0f, .y = 100.0f}},
+ AMOTION_EVENT_ACTION_MOVE}});
+
+ // Second pointer id=1 appears
+ mClientTestChannel->enqueueMessage(
+ nextPointerMessage({15ms,
+ {Pointer{.id = 0, .x = 100.0f, .y = 100.0f},
+ Pointer{.id = 1, .x = 500.0f, .y = 500.0f}},
+ actionPointer1Down}));
+
+ invokeLooperCallback();
+ mConsumer->consumeBatchedInputEvents(nanoseconds{20ms + RESAMPLE_LATENCY}.count());
+ // Not resampled value because requestedFrameTime - RESAMPLE_LATENCY == eventTime.
+ assertReceivedMotionEvent({InputEventEntry{15ms,
+ {Pointer{.id = 0, .x = 100.0f, .y = 100.0f},
+ Pointer{.id = 1, .x = 500.0f, .y = 500.0f}},
+ actionPointer1Down}});
+
+ // Both pointers move
+ mClientTestChannel->enqueueMessage(
+ nextPointerMessage({30ms,
+ {Pointer{.id = 0, .x = 100.0f, .y = 100.0f},
+ Pointer{.id = 1, .x = 500.0f, .y = 500.0f}},
+ AMOTION_EVENT_ACTION_MOVE}));
+ mClientTestChannel->enqueueMessage(
+ nextPointerMessage({40ms,
+ {Pointer{.id = 0, .x = 120.0f, .y = 120.0f},
+ Pointer{.id = 1, .x = 600.0f, .y = 600.0f}},
+ AMOTION_EVENT_ACTION_MOVE}));
+
+ invokeLooperCallback();
+ mConsumer->consumeBatchedInputEvents(nanoseconds{45ms + RESAMPLE_LATENCY}.count());
+ assertReceivedMotionEvent(
+ {InputEventEntry{30ms,
+ {Pointer{.id = 0, .x = 100.0f, .y = 100.0f},
+ Pointer{.id = 1, .x = 500.0f, .y = 500.0f}},
+ AMOTION_EVENT_ACTION_MOVE},
+ InputEventEntry{40ms,
+ {Pointer{.id = 0, .x = 120.0f, .y = 120.0f},
+ Pointer{.id = 1, .x = 600.0f, .y = 600.0f}},
+ AMOTION_EVENT_ACTION_MOVE},
+ InputEventEntry{45ms,
+ {Pointer{.id = 0, .x = 130.0f, .y = 130.0f, .isResampled = true},
+ Pointer{.id = 1, .x = 650.0f, .y = 650.0f, .isResampled = true}},
+ AMOTION_EVENT_ACTION_MOVE}});
+
+ // Both pointers move again
+ mClientTestChannel->enqueueMessage(
+ nextPointerMessage({60ms,
+ {Pointer{.id = 0, .x = 120.0f, .y = 120.0f},
+ Pointer{.id = 1, .x = 600.0f, .y = 600.0f}},
+ AMOTION_EVENT_ACTION_MOVE}));
+ mClientTestChannel->enqueueMessage(
+ nextPointerMessage({70ms,
+ {Pointer{.id = 0, .x = 130.0f, .y = 130.0f},
+ Pointer{.id = 1, .x = 700.0f, .y = 700.0f}},
+ AMOTION_EVENT_ACTION_MOVE}));
+
+ invokeLooperCallback();
+ mConsumer->consumeBatchedInputEvents(nanoseconds{75ms + RESAMPLE_LATENCY}.count());
+
+ /*
+ * The pointer id 0 at t = 60 should not be equal to 120 because the value was received twice,
+ * and resampled to 130. Therefore, if we reported 130, then we should continue to report it as
+ * such. Likewise, with pointer id 1.
+ */
+
+ // Not 120 because it matches a previous real event.
+ assertReceivedMotionEvent(
+ {InputEventEntry{60ms,
+ {Pointer{.id = 0, .x = 130.0f, .y = 130.0f, .isResampled = true},
+ Pointer{.id = 1, .x = 650.0f, .y = 650.0f, .isResampled = true}},
+ AMOTION_EVENT_ACTION_MOVE},
+ InputEventEntry{70ms,
+ {Pointer{.id = 0, .x = 130.0f, .y = 130.0f},
+ Pointer{.id = 1, .x = 700.0f, .y = 700.0f}},
+ AMOTION_EVENT_ACTION_MOVE},
+ InputEventEntry{75ms,
+ {Pointer{.id = 0, .x = 135.0f, .y = 135.0f, .isResampled = true},
+ Pointer{.id = 1, .x = 750.0f, .y = 750.0f, .isResampled = true}},
+ AMOTION_EVENT_ACTION_MOVE}});
+
+ // First pointer id=0 leaves the screen
+ mClientTestChannel->enqueueMessage(
+ nextPointerMessage({80ms,
+ {Pointer{.id = 0, .x = 120.0f, .y = 120.0f},
+ Pointer{.id = 1, .x = 600.0f, .y = 600.0f}},
+ actionPointer0Up}));
+
+ invokeLooperCallback();
+ // Not resampled event for ACTION_POINTER_UP
+ assertReceivedMotionEvent({InputEventEntry{80ms,
+ {Pointer{.id = 0, .x = 120.0f, .y = 120.0f},
+ Pointer{.id = 1, .x = 600.0f, .y = 600.0f}},
+ actionPointer0Up}});
+
+ // Remaining pointer id=1 is still present, but doesn't move
+ mClientTestChannel->enqueueMessage(nextPointerMessage(
+ {90ms, {Pointer{.id = 1, .x = 600.0f, .y = 600.0f}}, AMOTION_EVENT_ACTION_MOVE}));
+
+ invokeLooperCallback();
+ mConsumer->consumeBatchedInputEvents(nanoseconds{100ms}.count());
+
+ /*
+ * The latest event with ACTION_MOVE was at t = 70 with value = 700. Thus, the resampled value
+ * is 700 + ((95 - 70)/(90 - 70))*(600 - 700) = 575.
+ */
+ assertReceivedMotionEvent(
+ {InputEventEntry{90ms,
+ {Pointer{.id = 1, .x = 600.0f, .y = 600.0f}},
+ AMOTION_EVENT_ACTION_MOVE},
+ InputEventEntry{95ms,
+ {Pointer{.id = 1, .x = 575.0f, .y = 575.0f, .isResampled = true}},
+ AMOTION_EVENT_ACTION_MOVE}});
+}
+
} // namespace android
diff --git a/libs/input/tests/InputConsumer_test.cpp b/libs/input/tests/InputConsumer_test.cpp
index 6a3bbe5..06e19bb 100644
--- a/libs/input/tests/InputConsumer_test.cpp
+++ b/libs/input/tests/InputConsumer_test.cpp
@@ -194,7 +194,7 @@
std::unique_ptr<MotionEvent> moveMotionEvent =
assertReceivedMotionEvent(WithMotionAction(ACTION_MOVE));
ASSERT_NE(moveMotionEvent, nullptr);
- EXPECT_EQ(moveMotionEvent->getHistorySize() + 1, 3UL);
+ EXPECT_EQ(moveMotionEvent->getHistorySize() + 1, 2UL);
mClientTestChannel->assertFinishMessage(/*seq=*/0, /*handled=*/true);
mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true);
@@ -443,4 +443,5 @@
mClientTestChannel->assertFinishMessage(/*seq=*/8, /*handled=*/true);
mClientTestChannel->assertFinishMessage(/*seq=*/10, /*handled=*/true);
}
+
} // namespace android
diff --git a/libs/input/tests/Resampler_test.cpp b/libs/input/tests/Resampler_test.cpp
index fae8518..3162b77 100644
--- a/libs/input/tests/Resampler_test.cpp
+++ b/libs/input/tests/Resampler_test.cpp
@@ -648,7 +648,15 @@
mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample);
- assertMotionEventIsNotResampled(originalMotionEvent, motionEvent);
+ assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent,
+ {Pointer{.id = 0,
+ .x = 1.4f,
+ .y = 1.4f,
+ .isResampled = true},
+ Pointer{.id = 1,
+ .x = 2.4f,
+ .y = 2.4f,
+ .isResampled = true}});
}
TEST_F(ResamplerTest, MultiplePointerDifferentIdOrderExtrapolation) {
@@ -670,7 +678,15 @@
mResampler->resampleMotionEvent(16ms, secondMotionEvent, /*futureSample=*/nullptr);
- assertMotionEventIsNotResampled(secondOriginalMotionEvent, secondMotionEvent);
+ assertMotionEventIsResampledAndCoordsNear(secondOriginalMotionEvent, secondMotionEvent,
+ {Pointer{.id = 1,
+ .x = 4.4f,
+ .y = 4.4f,
+ .isResampled = true},
+ Pointer{.id = 0,
+ .x = 3.4f,
+ .y = 3.4f,
+ .isResampled = true}});
}
TEST_F(ResamplerTest, MultiplePointerDifferentIdsInterpolation) {
diff --git a/libs/input/tests/TouchResampling_test.cpp b/libs/input/tests/TouchResampling_test.cpp
index 8d8b530..9841c03 100644
--- a/libs/input/tests/TouchResampling_test.cpp
+++ b/libs/input/tests/TouchResampling_test.cpp
@@ -571,11 +571,12 @@
std::chrono::nanoseconds frameTime;
std::vector<InputEventEntry> entries, expectedEntries;
- // full action for when a pointer with id=1 appears (some other pointer must already be present)
+ // full action for when a pointer with index=1 appears (some other pointer must already be
+ // present)
constexpr int32_t actionPointer1Down =
AMOTION_EVENT_ACTION_POINTER_DOWN + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
- // full action for when a pointer with id=0 disappears (some other pointer must still remain)
+ // full action for when a pointer with index=0 disappears (some other pointer must still remain)
constexpr int32_t actionPointer0Up =
AMOTION_EVENT_ACTION_POINTER_UP + (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index d05ff34..5a78a5c 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -175,6 +175,14 @@
AHARDWAREBUFFER_FORMAT_YCbCr_P010 = 0x36,
/**
+ * YUV P210 format.
+ * Must have an even width and height. Can be accessed in OpenGL
+ * shaders through an external sampler. Does not support mip-maps
+ * cube-maps or multi-layered textures.
+ */
+ AHARDWAREBUFFER_FORMAT_YCbCr_P210 = 0x3c,
+
+ /**
* Corresponding formats:
* Vulkan: VK_FORMAT_R8_UNORM
* OpenGL ES: GR_GL_R8
diff --git a/libs/nativewindow/rust/Android.bp b/libs/nativewindow/rust/Android.bp
index c572ee7..faab48b 100644
--- a/libs/nativewindow/rust/Android.bp
+++ b/libs/nativewindow/rust/Android.bp
@@ -110,6 +110,7 @@
name: "libnativewindow_defaults",
srcs: ["src/lib.rs"],
rustlibs: [
+ "android.hardware.common-V2-rust",
"libbinder_rs",
"libbitflags",
"libnativewindow_bindgen",
diff --git a/libs/nativewindow/rust/src/handle.rs b/libs/nativewindow/rust/src/handle.rs
index c41ab8d..2b08c1b 100644
--- a/libs/nativewindow/rust/src/handle.rs
+++ b/libs/nativewindow/rust/src/handle.rs
@@ -12,6 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+use android_hardware_common::{
+ aidl::android::hardware::common::NativeHandle::NativeHandle as AidlNativeHandle,
+ binder::ParcelFileDescriptor,
+};
use std::{
ffi::c_int,
mem::forget,
@@ -81,6 +85,12 @@
/// Destroys the `NativeHandle`, taking ownership of the file descriptors it contained.
pub fn into_fds(self) -> Vec<OwnedFd> {
+ // Unset FDSan tag since this `native_handle_t` is no longer the owner of the file
+ // descriptors after this function.
+ // SAFETY: Our wrapped `native_handle_t` pointer is always valid.
+ unsafe {
+ ffi::native_handle_unset_fdsan_tag(self.as_ref());
+ }
let fds = self.data()[..self.fd_count()]
.iter()
.map(|fd| {
@@ -190,6 +200,21 @@
}
}
+impl From<AidlNativeHandle> for NativeHandle {
+ fn from(aidl_native_handle: AidlNativeHandle) -> Self {
+ let fds = aidl_native_handle.fds.into_iter().map(OwnedFd::from).collect();
+ Self::new(fds, &aidl_native_handle.ints).unwrap()
+ }
+}
+
+impl From<NativeHandle> for AidlNativeHandle {
+ fn from(native_handle: NativeHandle) -> Self {
+ let ints = native_handle.ints().to_owned();
+ let fds = native_handle.into_fds().into_iter().map(ParcelFileDescriptor::new).collect();
+ Self { ints, fds }
+ }
+}
+
// SAFETY: `NativeHandle` owns the `native_handle_t`, which just contains some integers and file
// descriptors, which aren't tied to any particular thread.
unsafe impl Send for NativeHandle {}
@@ -240,4 +265,43 @@
drop(cloned);
}
+
+ #[test]
+ fn to_fds() {
+ let file = File::open("/dev/null").unwrap();
+ let original = NativeHandle::new(vec![file.into()], &[42]).unwrap();
+ assert_eq!(original.ints(), &[42]);
+ assert_eq!(original.fds().len(), 1);
+
+ let fds = original.into_fds();
+ assert_eq!(fds.len(), 1);
+ }
+
+ #[test]
+ fn to_aidl() {
+ let file = File::open("/dev/null").unwrap();
+ let original = NativeHandle::new(vec![file.into()], &[42]).unwrap();
+ assert_eq!(original.ints(), &[42]);
+ assert_eq!(original.fds().len(), 1);
+
+ let aidl = AidlNativeHandle::from(original);
+ assert_eq!(&aidl.ints, &[42]);
+ assert_eq!(aidl.fds.len(), 1);
+ }
+
+ #[test]
+ fn to_from_aidl() {
+ let file = File::open("/dev/null").unwrap();
+ let original = NativeHandle::new(vec![file.into()], &[42]).unwrap();
+ assert_eq!(original.ints(), &[42]);
+ assert_eq!(original.fds().len(), 1);
+
+ let aidl = AidlNativeHandle::from(original);
+ assert_eq!(&aidl.ints, &[42]);
+ assert_eq!(aidl.fds.len(), 1);
+
+ let converted_back = NativeHandle::from(aidl);
+ assert_eq!(converted_back.ints(), &[42]);
+ assert_eq!(converted_back.fds().len(), 1);
+ }
}
diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs
index f19b908..a1d986e 100644
--- a/libs/nativewindow/rust/src/lib.rs
+++ b/libs/nativewindow/rust/src/lib.rs
@@ -220,7 +220,13 @@
Self(buffer)
}
- /// Get the internal |AHardwareBuffer| pointer without decrementing the refcount. This can
+ /// Get the internal `AHardwareBuffer` pointer that is only valid when this `HardwareBuffer`
+ /// exists. This can be used to provide a pointer to the AHB for a C/C++ API over the FFI.
+ pub fn as_raw(&self) -> NonNull<AHardwareBuffer> {
+ self.0
+ }
+
+ /// Get the internal `AHardwareBuffer` pointer without decrementing the refcount. This can
/// be used to provide a pointer to the AHB for a C/C++ API over the FFI.
pub fn into_raw(self) -> NonNull<AHardwareBuffer> {
let buffer = ManuallyDrop::new(self);
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index 859ae8b..ac43da8 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -16,6 +16,7 @@
#pragma once
+#include <gui/DisplayLuts.h>
#include <math/mat4.h>
#include <math/vec3.h>
#include <renderengine/ExternalTexture.h>
@@ -145,6 +146,8 @@
// If white point nits are unknown, then this layer is assumed to have the
// same luminance as the brightest layer in the scene.
float whitePointNits = -1.f;
+
+ std::shared_ptr<gui::DisplayLuts> luts;
};
// Keep in sync with custom comparison function in
@@ -187,7 +190,7 @@
lhs.blurRegionTransform == rhs.blurRegionTransform &&
lhs.stretchEffect == rhs.stretchEffect &&
lhs.edgeExtensionEffect == rhs.edgeExtensionEffect &&
- lhs.whitePointNits == rhs.whitePointNits;
+ lhs.whitePointNits == rhs.whitePointNits && lhs.luts == rhs.luts;
}
static inline void PrintTo(const Buffer& settings, ::std::ostream* os) {
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index 5159ffe..b19a862 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -135,6 +135,9 @@
"EGL/MultifileBlobCache.cpp",
],
export_include_dirs: ["EGL"],
+ shared_libs: [
+ "libz",
+ ],
}
cc_library_shared {
@@ -169,6 +172,7 @@
"libutils",
"libSurfaceFlingerProp",
"libunwindstack",
+ "libz",
],
static_libs: [
"libEGL_getProcAddress",
@@ -199,6 +203,7 @@
],
shared_libs: [
"libutils",
+ "libz",
],
}
diff --git a/opengl/libs/EGL/FileBlobCache.cpp b/opengl/libs/EGL/FileBlobCache.cpp
index 4a0fac4..573ca54 100644
--- a/opengl/libs/EGL/FileBlobCache.cpp
+++ b/opengl/libs/EGL/FileBlobCache.cpp
@@ -27,6 +27,7 @@
#include <log/log.h>
#include <utils/Trace.h>
+#include <zlib.h>
// Cache file header
static const char* cacheFileMagic = "EGL$";
@@ -34,20 +35,10 @@
namespace android {
-uint32_t crc32c(const uint8_t* buf, size_t len) {
- const uint32_t polyBits = 0x82F63B78;
- uint32_t r = 0;
- for (size_t i = 0; i < len; i++) {
- r ^= buf[i];
- for (int j = 0; j < 8; j++) {
- if (r & 1) {
- r = (r >> 1) ^ polyBits;
- } else {
- r >>= 1;
- }
- }
- }
- return r;
+uint32_t GenerateCRC32(const uint8_t *data, size_t size)
+{
+ const unsigned long initialValue = crc32_z(0u, nullptr, 0u);
+ return static_cast<uint32_t>(crc32_z(initialValue, data, size));
}
FileBlobCache::FileBlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize,
@@ -101,7 +92,7 @@
return;
}
uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4);
- if (crc32c(buf + headerSize, cacheSize) != *crc) {
+ if (GenerateCRC32(buf + headerSize, cacheSize) != *crc) {
ALOGE("cache file failed CRC check");
close(fd);
return;
@@ -175,7 +166,7 @@
// Write the file magic and CRC
memcpy(buf, cacheFileMagic, 4);
uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4);
- *crc = crc32c(buf + headerSize, cacheSize);
+ *crc = GenerateCRC32(buf + headerSize, cacheSize);
if (write(fd, buf, fileSize) == -1) {
ALOGE("error writing cache file: %s (%d)", strerror(errno),
diff --git a/opengl/libs/EGL/FileBlobCache.h b/opengl/libs/EGL/FileBlobCache.h
index f083b0d..224444d 100644
--- a/opengl/libs/EGL/FileBlobCache.h
+++ b/opengl/libs/EGL/FileBlobCache.h
@@ -22,7 +22,7 @@
namespace android {
-uint32_t crc32c(const uint8_t* buf, size_t len);
+uint32_t GenerateCRC32(const uint8_t *data, size_t size);
class FileBlobCache : public BlobCache {
public:
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 3be8ddc..7012df2 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -548,6 +548,10 @@
.flags = ANDROID_DLEXT_USE_NAMESPACE,
.library_namespace = ns,
};
+ auto prop = base::GetProperty("debug.angle.libs.suffix", "");
+ if (!prop.empty()) {
+ name = std::string("lib") + kind + "_" + prop + ".so";
+ }
so = do_android_dlopen_ext(name.c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo);
}
diff --git a/opengl/libs/EGL/MultifileBlobCache.cpp b/opengl/libs/EGL/MultifileBlobCache.cpp
index 9905210..f7e33b3 100644
--- a/opengl/libs/EGL/MultifileBlobCache.cpp
+++ b/opengl/libs/EGL/MultifileBlobCache.cpp
@@ -214,9 +214,8 @@
}
// Ensure we have a good CRC
- if (header.crc !=
- crc32c(mappedEntry + sizeof(MultifileHeader),
- fileSize - sizeof(MultifileHeader))) {
+ if (header.crc != GenerateCRC32(mappedEntry + sizeof(MultifileHeader),
+ fileSize - sizeof(MultifileHeader))) {
ALOGV("INIT: Entry %u failed CRC check! Removing.", entryHash);
if (remove(fullPath.c_str()) != 0) {
ALOGE("Error removing %s: %s", fullPath.c_str(), std::strerror(errno));
@@ -532,9 +531,9 @@
mBuildId.length() > PROP_VALUE_MAX ? PROP_VALUE_MAX : mBuildId.length());
// Finally update the crc, using cacheVersion and everything the follows
- status.crc =
- crc32c(reinterpret_cast<uint8_t*>(&status) + offsetof(MultifileStatus, cacheVersion),
- sizeof(status) - offsetof(MultifileStatus, cacheVersion));
+ status.crc = GenerateCRC32(
+ reinterpret_cast<uint8_t *>(&status) + offsetof(MultifileStatus, cacheVersion),
+ sizeof(status) - offsetof(MultifileStatus, cacheVersion));
// Create the status file
std::string cacheStatus = baseDir + "/" + kMultifileBlobCacheStatusFile;
@@ -599,9 +598,9 @@
}
// Ensure we have a good CRC
- if (status.crc !=
- crc32c(reinterpret_cast<uint8_t*>(&status) + offsetof(MultifileStatus, cacheVersion),
- sizeof(status) - offsetof(MultifileStatus, cacheVersion))) {
+ if (status.crc != GenerateCRC32(reinterpret_cast<uint8_t *>(&status) +
+ offsetof(MultifileStatus, cacheVersion),
+ sizeof(status) - offsetof(MultifileStatus, cacheVersion))) {
ALOGE("STATUS(CHECK): Cache status failed CRC check!");
return false;
}
@@ -840,8 +839,8 @@
// Add CRC check to the header (always do this last!)
MultifileHeader* header = reinterpret_cast<MultifileHeader*>(buffer);
- header->crc =
- crc32c(buffer + sizeof(MultifileHeader), bufferSize - sizeof(MultifileHeader));
+ header->crc = GenerateCRC32(buffer + sizeof(MultifileHeader),
+ bufferSize - sizeof(MultifileHeader));
ssize_t result = write(fd, buffer, bufferSize);
if (result != bufferSize) {
diff --git a/opengl/libs/EGL/MultifileBlobCache.h b/opengl/libs/EGL/MultifileBlobCache.h
index 18566c2..65aa2db 100644
--- a/opengl/libs/EGL/MultifileBlobCache.h
+++ b/opengl/libs/EGL/MultifileBlobCache.h
@@ -34,7 +34,7 @@
namespace android {
-constexpr uint32_t kMultifileBlobCacheVersion = 1;
+constexpr uint32_t kMultifileBlobCacheVersion = 2;
constexpr char kMultifileBlobCacheStatusFile[] = "cache.status";
struct MultifileHeader {
diff --git a/opengl/libs/EGL/fuzzer/Android.bp b/opengl/libs/EGL/fuzzer/Android.bp
index 022a2a3..4947e5f 100644
--- a/opengl/libs/EGL/fuzzer/Android.bp
+++ b/opengl/libs/EGL/fuzzer/Android.bp
@@ -36,6 +36,10 @@
"libutils",
],
+ shared_libs: [
+ "libz",
+ ],
+
srcs: [
"MultifileBlobCache_fuzzer.cpp",
],
diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp
index 503d7df..839a5ca 100644
--- a/opengl/tests/EGLTest/EGL_test.cpp
+++ b/opengl/tests/EGLTest/EGL_test.cpp
@@ -765,6 +765,30 @@
}
}
+// Verify that eglCreateContext works when EGL_TELEMETRY_HINT_ANDROID is used with
+// NO_HINT = 0, SKIP_TELEMETRY = 1 and an invalid of value of 2
+TEST_F(EGLTest, EGLContextTelemetryHintExt) {
+ for (int i = 0; i < 3; i++) {
+ EGLConfig config;
+ get8BitConfig(config);
+ std::vector<EGLint> contextAttributes;
+ contextAttributes.reserve(4);
+ contextAttributes.push_back(EGL_TELEMETRY_HINT_ANDROID);
+ contextAttributes.push_back(i);
+ contextAttributes.push_back(EGL_NONE);
+ contextAttributes.push_back(EGL_NONE);
+
+ EGLContext eglContext = eglCreateContext(mEglDisplay, config, EGL_NO_CONTEXT,
+ contextAttributes.data());
+ EXPECT_NE(EGL_NO_CONTEXT, eglContext);
+ EXPECT_EQ(EGL_SUCCESS, eglGetError());
+
+ if (eglContext != EGL_NO_CONTEXT) {
+ eglDestroyContext(mEglDisplay, eglContext);
+ }
+ }
+}
+
// Emulate what a native application would do to create a
// 10:10:10:2 surface.
TEST_F(EGLTest, EGLConfig1010102) {
diff --git a/services/gpuservice/vts/Android.bp b/services/gpuservice/vts/Android.bp
index a24822a..6e0a9f7 100644
--- a/services/gpuservice/vts/Android.bp
+++ b/services/gpuservice/vts/Android.bp
@@ -13,6 +13,7 @@
// limitations under the License.
package {
+ default_team: "trendy_team_android_gpu",
default_applicable_licenses: ["frameworks_native_license"],
}
diff --git a/services/inputflinger/InputDeviceMetricsSource.cpp b/services/inputflinger/InputDeviceMetricsSource.cpp
index dee4cb8..70262fb 100644
--- a/services/inputflinger/InputDeviceMetricsSource.cpp
+++ b/services/inputflinger/InputDeviceMetricsSource.cpp
@@ -50,6 +50,18 @@
return InputDeviceUsageSource::BUTTONS;
}
+std::set<InputDeviceUsageSource> getUsageSourcesForKeyArgs(
+ const NotifyKeyArgs& args, const std::vector<InputDeviceInfo>& inputDevices) {
+ int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NONE;
+ for (const InputDeviceInfo& inputDevice : inputDevices) {
+ if (args.deviceId == inputDevice.getId()) {
+ keyboardType = inputDevice.getKeyboardType();
+ break;
+ }
+ }
+ return std::set{getUsageSourceForKeyArgs(keyboardType, args)};
+}
+
std::set<InputDeviceUsageSource> getUsageSourcesForMotionArgs(const NotifyMotionArgs& motionArgs) {
LOG_ALWAYS_FATAL_IF(motionArgs.getPointerCount() < 1, "Received motion args without pointers");
std::set<InputDeviceUsageSource> sources;
diff --git a/services/inputflinger/InputDeviceMetricsSource.h b/services/inputflinger/InputDeviceMetricsSource.h
index a6be8f4..702badd 100644
--- a/services/inputflinger/InputDeviceMetricsSource.h
+++ b/services/inputflinger/InputDeviceMetricsSource.h
@@ -54,6 +54,10 @@
/** Returns the InputDeviceUsageSource that corresponds to the key event. */
InputDeviceUsageSource getUsageSourceForKeyArgs(int32_t keyboardType, const NotifyKeyArgs&);
+/** Returns the InputDeviceUsageSources that correspond to the key event. */
+std::set<InputDeviceUsageSource> getUsageSourcesForKeyArgs(
+ const NotifyKeyArgs&, const std::vector<InputDeviceInfo>& inputDevices);
+
/** Returns the InputDeviceUsageSources that correspond to the motion event. */
std::set<InputDeviceUsageSource> getUsageSourcesForMotionArgs(const NotifyMotionArgs&);
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 602904f..4f9d9e4 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -4551,7 +4551,7 @@
if (args.id != android::os::IInputConstants::INVALID_INPUT_EVENT_ID &&
IdGenerator::getSource(args.id) == IdGenerator::Source::INPUT_READER &&
!mInputFilterEnabled) {
- mLatencyTracker.trackNotifyKey(args);
+ mLatencyTracker.trackListener(args);
}
}
@@ -4687,7 +4687,7 @@
if (args.id != android::os::IInputConstants::INVALID_INPUT_EVENT_ID &&
IdGenerator::getSource(args.id) == IdGenerator::Source::INPUT_READER &&
!mInputFilterEnabled) {
- mLatencyTracker.trackNotifyMotion(args);
+ mLatencyTracker.trackListener(args);
}
needWake = enqueueInboundEventLocked(std::move(newEntry));
diff --git a/services/inputflinger/dispatcher/LatencyTracker.cpp b/services/inputflinger/dispatcher/LatencyTracker.cpp
index 0852026..0921e37 100644
--- a/services/inputflinger/dispatcher/LatencyTracker.cpp
+++ b/services/inputflinger/dispatcher/LatencyTracker.cpp
@@ -20,6 +20,7 @@
#include <inttypes.h>
+#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android/os/IInputConstants.h>
@@ -32,6 +33,8 @@
namespace android::inputdispatcher {
+namespace {
+
/**
* Events that are older than this time will be considered mature, at which point we will stop
* waiting for the apps to provide further information about them.
@@ -62,27 +65,25 @@
}
}
+} // namespace
+
LatencyTracker::LatencyTracker(InputEventTimelineProcessor& processor)
: mTimelineProcessor(&processor) {}
-void LatencyTracker::trackNotifyMotion(const NotifyMotionArgs& args) {
- std::set<InputDeviceUsageSource> sources = getUsageSourcesForMotionArgs(args);
- trackListener(args.id, args.eventTime, args.readTime, args.deviceId, sources, args.action,
- InputEventType::MOTION);
-}
+void LatencyTracker::trackListener(const NotifyArgs& args) {
+ if (const NotifyKeyArgs* keyArgs = std::get_if<NotifyKeyArgs>(&args)) {
+ std::set<InputDeviceUsageSource> sources =
+ getUsageSourcesForKeyArgs(*keyArgs, mInputDevices);
+ trackListener(keyArgs->id, keyArgs->eventTime, keyArgs->readTime, keyArgs->deviceId,
+ sources, keyArgs->action, InputEventType::KEY);
-void LatencyTracker::trackNotifyKey(const NotifyKeyArgs& args) {
- int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NONE;
- for (auto& inputDevice : mInputDevices) {
- if (args.deviceId == inputDevice.getId()) {
- keyboardType = inputDevice.getKeyboardType();
- break;
- }
+ } else if (const NotifyMotionArgs* motionArgs = std::get_if<NotifyMotionArgs>(&args)) {
+ std::set<InputDeviceUsageSource> sources = getUsageSourcesForMotionArgs(*motionArgs);
+ trackListener(motionArgs->id, motionArgs->eventTime, motionArgs->readTime,
+ motionArgs->deviceId, sources, motionArgs->action, InputEventType::MOTION);
+ } else {
+ LOG(FATAL) << "Unexpected NotifyArgs type: " << args.index();
}
- std::set<InputDeviceUsageSource> sources =
- std::set{getUsageSourceForKeyArgs(keyboardType, args)};
- trackListener(args.id, args.eventTime, args.readTime, args.deviceId, sources, args.action,
- InputEventType::KEY);
}
void LatencyTracker::trackListener(int32_t inputEventId, nsecs_t eventTime, nsecs_t readTime,
diff --git a/services/inputflinger/dispatcher/LatencyTracker.h b/services/inputflinger/dispatcher/LatencyTracker.h
index eb58222..79ea14c 100644
--- a/services/inputflinger/dispatcher/LatencyTracker.h
+++ b/services/inputflinger/dispatcher/LatencyTracker.h
@@ -44,28 +44,20 @@
*/
LatencyTracker(InputEventTimelineProcessor& processor);
/**
- * Start keeping track of an event identified by inputEventId. This must be called first.
+ * Start keeping track of an event identified by the args. This must be called first.
* If duplicate events are encountered (events that have the same eventId), none of them will be
- * tracked. This is because there is not enough information to correctly track them. The api's
- * 'trackFinishedEvent' and 'trackGraphicsLatency' only contain the inputEventId, and not the
- * eventTime. Even if eventTime was provided, there would still be a possibility of having
- * duplicate events that happen to have the same eventTime and inputEventId. Therefore, we
- * must drop all duplicate data.
+ * tracked. This is because there is not enough information to correctly track them. It is
+ * always possible that two different events are generated with the same inputEventId and the
+ * same eventTime, so there aren't ways to distinguish those. Therefore, we must drop all
+ * duplicate data.
+ * For that reason, the APIs 'trackFinishedEvent' and 'trackGraphicsLatency' only receive the
+ * inputEventId as input.
*/
- void trackListener(int32_t inputEventId, nsecs_t eventTime, nsecs_t readTime, DeviceId deviceId,
- const std::set<InputDeviceUsageSource>& sources, int32_t inputEventAction,
- InputEventType inputEventType);
+ void trackListener(const NotifyArgs& args);
void trackFinishedEvent(int32_t inputEventId, const sp<IBinder>& connectionToken,
nsecs_t deliveryTime, nsecs_t consumeTime, nsecs_t finishTime);
void trackGraphicsLatency(int32_t inputEventId, const sp<IBinder>& connectionToken,
std::array<nsecs_t, GraphicsTimeline::SIZE> timeline);
- /**
- * trackNotifyMotion and trackNotifyKeys are intermediates between InputDispatcher and
- * trackListener. They compute the InputDeviceUsageSource set and call trackListener with
- * the relevant parameters for latency computation.
- */
- void trackNotifyMotion(const NotifyMotionArgs& args);
- void trackNotifyKey(const NotifyKeyArgs& args);
std::string dump(const char* prefix) const;
void setInputDevices(const std::vector<InputDeviceInfo>& inputDevices);
@@ -90,6 +82,10 @@
InputEventTimelineProcessor* mTimelineProcessor;
std::vector<InputDeviceInfo> mInputDevices;
+
+ void trackListener(int32_t inputEventId, nsecs_t eventTime, nsecs_t readTime, DeviceId deviceId,
+ const std::set<InputDeviceUsageSource>& sources, int32_t inputEventAction,
+ InputEventType inputEventType);
void reportAndPruneMatureRecords(nsecs_t newEventTime);
};
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index 756a29b..6ef4a3d 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -137,19 +137,18 @@
ui::LogicalDisplayId defaultPointerDisplayId;
// The mouse pointer speed, as a number from -7 (slowest) to 7 (fastest).
- //
- // Currently only used when the enable_new_mouse_pointer_ballistics flag is enabled.
int32_t mousePointerSpeed;
// Displays on which an acceleration curve shouldn't be applied for pointer movements from mice.
- //
- // Currently only used when the enable_new_mouse_pointer_ballistics flag is enabled.
std::set<ui::LogicalDisplayId> displaysWithMousePointerAccelerationDisabled;
- // Velocity control parameters for mouse pointer movements.
+ // Velocity control parameters for touchpad pointer movements on the old touchpad stack (based
+ // on TouchInputMapper).
//
- // If the enable_new_mouse_pointer_ballistics flag is enabled, these are ignored and the values
- // of mousePointerSpeed and mousePointerAccelerationEnabled used instead.
+ // For mice, these are ignored and the values of mousePointerSpeed and
+ // mousePointerAccelerationEnabled used instead.
+ //
+ // TODO(b/281840344): remove this.
VelocityControlParameters pointerVelocityControlParameters;
// Velocity control parameters for mouse wheel movements.
@@ -426,6 +425,16 @@
/* Notifies that mouse cursor faded due to typing. */
virtual void notifyMouseCursorFadedOnTyping() = 0;
+
+ /* Set whether the given input device can wake up the kernel from sleep
+ * when it generates input events. By default, usually only internal (built-in)
+ * input devices can wake the kernel from sleep. For an external input device
+ * that supports remote wakeup to be able to wake the kernel, this must be called
+ * after each time the device is connected/added.
+ *
+ * Returns true if setting power wakeup was successful.
+ */
+ virtual bool setKernelWakeEnabled(int32_t deviceId, bool enabled) = 0;
};
// --- TouchAffineTransformation ---
diff --git a/services/inputflinger/include/NotifyArgsBuilders.h b/services/inputflinger/include/NotifyArgsBuilders.h
index 5b94d57..13eaaf3 100644
--- a/services/inputflinger/include/NotifyArgsBuilders.h
+++ b/services/inputflinger/include/NotifyArgsBuilders.h
@@ -24,13 +24,15 @@
#include <input/Keyboard.h>
#include <utils/Timers.h> // for nsecs_t, systemTime
+#include <cstdint>
#include <vector>
namespace android {
class MotionArgsBuilder {
public:
- MotionArgsBuilder(int32_t action, int32_t source) : mEventId(InputEvent::nextId()) {
+ MotionArgsBuilder(int32_t action, int32_t source, int32_t eventId = InputEvent::nextId())
+ : mEventId(eventId) {
mAction = action;
if (mAction == AMOTION_EVENT_ACTION_CANCEL) {
addFlag(AMOTION_EVENT_FLAG_CANCELED);
@@ -55,6 +57,11 @@
return *this;
}
+ MotionArgsBuilder& readTime(nsecs_t readTime) {
+ mReadTime = readTime;
+ return *this;
+ }
+
MotionArgsBuilder& displayId(ui::LogicalDisplayId displayId) {
mDisplayId = displayId;
return *this;
@@ -121,7 +128,7 @@
return {mEventId,
mEventTime,
- /*readTime=*/mEventTime,
+ mReadTime.value_or(mEventTime),
mDeviceId,
mSource,
mDisplayId,
@@ -151,6 +158,7 @@
uint32_t mSource;
nsecs_t mDownTime;
nsecs_t mEventTime;
+ std::optional<nsecs_t> mReadTime;
ui::LogicalDisplayId mDisplayId{ui::LogicalDisplayId::DEFAULT};
uint32_t mPolicyFlags = DEFAULT_POLICY_FLAGS;
int32_t mActionButton{0};
@@ -165,7 +173,8 @@
class KeyArgsBuilder {
public:
- KeyArgsBuilder(int32_t action, int32_t source) : mEventId(InputEvent::nextId()) {
+ KeyArgsBuilder(int32_t action, int32_t source, int32_t eventId = InputEvent::nextId())
+ : mEventId(eventId) {
mAction = action;
mSource = source;
mEventTime = systemTime(SYSTEM_TIME_MONOTONIC);
@@ -187,6 +196,11 @@
return *this;
}
+ KeyArgsBuilder& readTime(nsecs_t readTime) {
+ mReadTime = readTime;
+ return *this;
+ }
+
KeyArgsBuilder& displayId(ui::LogicalDisplayId displayId) {
mDisplayId = displayId;
return *this;
@@ -214,18 +228,10 @@
}
NotifyKeyArgs build() const {
- return {mEventId,
- mEventTime,
- /*readTime=*/mEventTime,
- mDeviceId,
- mSource,
- mDisplayId,
- mPolicyFlags,
- mAction,
- mFlags,
- mKeyCode,
- mScanCode,
- mMetaState,
+ return {mEventId, mEventTime, mReadTime.value_or(mEventTime),
+ mDeviceId, mSource, mDisplayId,
+ mPolicyFlags, mAction, mFlags,
+ mKeyCode, mScanCode, mMetaState,
mDownTime};
}
@@ -236,6 +242,7 @@
uint32_t mSource;
nsecs_t mDownTime;
nsecs_t mEventTime;
+ std::optional<nsecs_t> mReadTime;
ui::LogicalDisplayId mDisplayId{ui::LogicalDisplayId::DEFAULT};
uint32_t mPolicyFlags = DEFAULT_POLICY_FLAGS;
int32_t mFlags{0};
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index f8cd973..35ba48f 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -43,6 +43,7 @@
#include <android-base/strings.h>
#include <cutils/properties.h>
#include <ftl/enum.h>
+#include <input/InputEventLabels.h>
#include <input/KeyCharacterMap.h>
#include <input/KeyLayoutMap.h>
#include <input/PrintTools.h>
@@ -1021,6 +1022,8 @@
std::scoped_lock _l(mLock);
const Device* device = getDeviceLocked(deviceId);
if (device == nullptr) {
+ ALOGE("Couldn't find device with ID %d, so returning null axis info for axis %s", deviceId,
+ InputEventLookup::getLinuxEvdevLabel(EV_ABS, axis, 0).code.c_str());
return std::nullopt;
}
// We can read the RawAbsoluteAxisInfo even if the device is disabled and doesn't have a valid
@@ -2848,6 +2851,35 @@
mNeedToReopenDevices = true;
}
+bool EventHub::setKernelWakeEnabled(int32_t deviceId, bool enabled) {
+ std::scoped_lock _l(mLock);
+ std::string enabledStr = enabled ? "enabled" : "disabled";
+ Device* device = getDeviceLocked(deviceId);
+ if (device == nullptr) {
+ ALOGE("Device Id %d does not exist for setting power wakeup", deviceId);
+ return false;
+ }
+ if (device->associatedDevice == nullptr) {
+ return false;
+ }
+ std::filesystem::path currentPath = device->associatedDevice->sysfsRootPath;
+ while (!currentPath.empty() && currentPath != "/") {
+ std::string nodePath = currentPath / "power/wakeup";
+ if (std::filesystem::exists(nodePath)) {
+ if (base::WriteStringToFile(enabledStr, nodePath)) {
+ return true;
+
+ }
+ // No need to continue searching in parent directories as power/wakeup nodes
+ // higher up may control other subdevices.
+ ALOGW("Failed to set power/wakeup node at %s", nodePath.c_str());
+ return false;
+ }
+ currentPath = currentPath.parent_path();
+ }
+ return false;
+}
+
void EventHub::dump(std::string& dump) const {
dump += "Event Hub State:\n";
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index 02eeb0a..5e42d57 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -745,6 +745,14 @@
}
}
+bool InputDevice::setKernelWakeEnabled(bool enabled) {
+ bool success = false;
+ for_each_subdevice([&enabled, &success](InputDeviceContext& context) {
+ success |= context.setKernelWakeEnabled(enabled);
+ });
+ return success;
+}
+
InputDeviceContext::InputDeviceContext(InputDevice& device, int32_t eventHubId)
: mDevice(device),
mContext(device.getContext()),
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index ab27042..a2b7e82 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -901,6 +901,16 @@
mPreventingTouchpadTaps = true;
}
+bool InputReader::setKernelWakeEnabled(int32_t deviceId, bool enabled) {
+ std::scoped_lock _l(mLock);
+
+ InputDevice* device = findInputDeviceLocked(deviceId);
+ if (device) {
+ return device->setKernelWakeEnabled(enabled);
+ }
+ return false;
+}
+
void InputReader::dump(std::string& dump) {
std::scoped_lock _l(mLock);
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index dffd8e3..4336945 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -396,6 +396,13 @@
/* Sysfs node changed. Reopen the Eventhub device if any new Peripheral like Light, Battery,
* etc. is detected. */
virtual void sysfsNodeChanged(const std::string& sysfsNodePath) = 0;
+
+ /* Set whether the given input device can wake up the kernel from sleep
+ * when it generates input events. By default, usually only internal (built-in)
+ * input devices can wake the kernel from sleep. For an external input device
+ * that supports remote wakeup to be able to wake the kernel, this must be called
+ * after each time the device is connected/added. */
+ virtual bool setKernelWakeEnabled(int32_t deviceId, bool enabled) = 0;
};
template <std::size_t BITS>
@@ -603,6 +610,8 @@
void sysfsNodeChanged(const std::string& sysfsNodePath) override final;
+ bool setKernelWakeEnabled(int32_t deviceId, bool enabled) override final;
+
~EventHub() override;
private:
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index 8958d9e..abe7a5f 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -139,6 +139,8 @@
std::optional<HardwareProperties> getTouchpadHardwareProperties();
+ bool setKernelWakeEnabled(bool enabled);
+
// construct and add a mapper to the input device
template <class T, typename... Args>
T& addMapper(int32_t eventHubId, Args... args) {
@@ -469,6 +471,9 @@
inline void setKeyboardType(KeyboardType keyboardType) {
return mDevice.setKeyboardType(keyboardType);
}
+ inline bool setKernelWakeEnabled(bool enabled) {
+ return mEventHub->setKernelWakeEnabled(mId, enabled);
+ }
private:
InputDevice& mDevice;
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 1003871..7614a05 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -120,6 +120,8 @@
void notifyMouseCursorFadedOnTyping() override;
+ bool setKernelWakeEnabled(int32_t deviceId, bool enabled) override;
+
protected:
// These members are protected so they can be instrumented by test cases.
virtual std::shared_ptr<InputDevice> createDeviceLocked(nsecs_t when, int32_t deviceId,
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index 630bd9b..b33659c 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -33,8 +33,6 @@
#include "input/PrintTools.h"
-namespace input_flags = com::android::input::flags;
-
namespace android {
// The default velocity control parameters that has no effect.
@@ -77,8 +75,7 @@
CursorInputMapper::CursorInputMapper(InputDeviceContext& deviceContext,
const InputReaderConfiguration& readerConfig)
: InputMapper(deviceContext, readerConfig),
- mLastEventTime(std::numeric_limits<nsecs_t>::min()),
- mEnableNewMousePointerBallistics(input_flags::enable_new_mouse_pointer_ballistics()) {}
+ mLastEventTime(std::numeric_limits<nsecs_t>::min()) {}
uint32_t CursorInputMapper::getSources() const {
return mSource;
@@ -207,8 +204,7 @@
mDownTime = 0;
mLastEventTime = std::numeric_limits<nsecs_t>::min();
- mOldPointerVelocityControl.reset();
- mNewPointerVelocityControl.reset();
+ mPointerVelocityControl.reset();
mWheelXVelocityControl.reset();
mWheelYVelocityControl.reset();
@@ -291,11 +287,7 @@
mWheelYVelocityControl.move(when, nullptr, &vscroll);
mWheelXVelocityControl.move(when, &hscroll, nullptr);
- if (mEnableNewMousePointerBallistics) {
- mNewPointerVelocityControl.move(when, &deltaX, &deltaY);
- } else {
- mOldPointerVelocityControl.move(when, &deltaX, &deltaY);
- }
+ mPointerVelocityControl.move(when, &deltaX, &deltaY);
float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
@@ -486,27 +478,15 @@
void CursorInputMapper::configureOnChangePointerSpeed(const InputReaderConfiguration& config) {
if (mParameters.mode == Parameters::Mode::POINTER_RELATIVE) {
// Disable any acceleration or scaling for the pointer when Pointer Capture is enabled.
- if (mEnableNewMousePointerBallistics) {
- mNewPointerVelocityControl.setAccelerationEnabled(false);
- } else {
- mOldPointerVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS);
- }
+ mPointerVelocityControl.setAccelerationEnabled(false);
mWheelXVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS);
mWheelYVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS);
} else {
- if (mEnableNewMousePointerBallistics) {
- mNewPointerVelocityControl.setAccelerationEnabled(
- config.displaysWithMousePointerAccelerationDisabled.count(
- mDisplayId.value_or(ui::LogicalDisplayId::INVALID)) == 0);
- mNewPointerVelocityControl.setCurve(
- createAccelerationCurveForPointerSensitivity(config.mousePointerSpeed));
- } else {
- mOldPointerVelocityControl.setParameters(
- (config.displaysWithMousePointerAccelerationDisabled.count(
- mDisplayId.value_or(ui::LogicalDisplayId::INVALID)) == 0)
- ? config.pointerVelocityControlParameters
- : FLAT_VELOCITY_CONTROL_PARAMS);
- }
+ mPointerVelocityControl.setAccelerationEnabled(
+ config.displaysWithMousePointerAccelerationDisabled.count(
+ mDisplayId.value_or(ui::LogicalDisplayId::INVALID)) == 0);
+ mPointerVelocityControl.setCurve(
+ createAccelerationCurveForPointerSensitivity(config.mousePointerSpeed));
mWheelXVelocityControl.setParameters(config.wheelVelocityControlParameters);
mWheelYVelocityControl.setParameters(config.wheelVelocityControlParameters);
}
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h
index 403e96d..8319922 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.h
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.h
@@ -104,8 +104,7 @@
// Velocity controls for mouse pointer and wheel movements.
// The controls for X and Y wheel movements are separate to keep them decoupled.
- SimpleVelocityControl mOldPointerVelocityControl;
- CurvedVelocityControl mNewPointerVelocityControl;
+ CurvedVelocityControl mPointerVelocityControl;
SimpleVelocityControl mWheelXVelocityControl;
SimpleVelocityControl mWheelYVelocityControl;
@@ -120,7 +119,6 @@
nsecs_t mDownTime;
nsecs_t mLastEventTime;
- const bool mEnableNewMousePointerBallistics;
bool mMouseReverseVerticalScrolling = false;
explicit CursorInputMapper(InputDeviceContext& deviceContext,
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
index 567a3e2..fe3e4c2 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -132,7 +132,9 @@
void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo& info) {
InputMapper::populateDeviceInfo(info);
- info.setKeyCharacterMap(getDeviceContext().getKeyCharacterMap());
+ if (const auto kcm = getDeviceContext().getKeyCharacterMap(); kcm != nullptr) {
+ info.setKeyCharacterMap(std::make_unique<KeyCharacterMap>(*kcm));
+ }
std::optional keyboardLayoutInfo = getKeyboardLayoutInfo();
if (keyboardLayoutInfo) {
@@ -241,11 +243,16 @@
mHidUsageAccumulator.process(rawEvent);
switch (rawEvent.type) {
case EV_KEY: {
- int32_t scanCode = rawEvent.code;
+ // Skip processing repeated keys (value == 2) since auto repeat is handled by Android
+ // internally.
+ if (rawEvent.value == 2) {
+ break;
+ }
+ const int32_t scanCode = rawEvent.code;
if (isSupportedScanCode(scanCode)) {
- out += processKey(rawEvent.when, rawEvent.readTime, rawEvent.value != 0,
- scanCode, mHidUsageAccumulator.consumeCurrentHidUsage());
+ out += processKey(rawEvent.when, rawEvent.readTime, rawEvent.value != 0, scanCode,
+ mHidUsageAccumulator.consumeCurrentHidUsage());
}
break;
}
@@ -337,12 +344,14 @@
}
KeyboardType keyboardType = getDeviceContext().getKeyboardType();
- // Any key down on an external keyboard should wake the device.
- // We don't do this for internal keyboards to prevent them from waking up in your pocket.
+ // Any key down on an external keyboard or internal alphanumeric keyboard should wake the
+ // device. We don't do this for non-alphanumeric internal keyboards to prevent them from
+ // waking up in your pocket.
// For internal keyboards and devices for which the default wake behavior is explicitly
// prevented (e.g. TV remotes), the key layout file should specify the policy flags for each
// wake key individually.
- if (down && getDeviceContext().isExternal() && !mParameters.doNotWakeByDefault &&
+ if (down && !mParameters.doNotWakeByDefault &&
+ (getDeviceContext().isExternal() || wakeOnAlphabeticKeyboard(keyboardType)) &&
!(keyboardType != KeyboardType::ALPHABETIC && isMediaKey(keyCode))) {
policyFlags |= POLICY_FLAG_WAKE;
}
@@ -500,4 +509,8 @@
return deviceSources & ALL_KEYBOARD_SOURCES;
}
+bool KeyboardInputMapper::wakeOnAlphabeticKeyboard(const KeyboardType keyboardType) const {
+ return mEnableAlphabeticKeyboardWakeFlag && (KeyboardType::ALPHABETIC == keyboardType);
+}
+
} // namespace android
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.h b/services/inputflinger/reader/mapper/KeyboardInputMapper.h
index 10bd424..7d9b3e4 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.h
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.h
@@ -16,6 +16,8 @@
#pragma once
+#include <com_android_input_flags.h>
+
#include "HidUsageAccumulator.h"
#include "InputMapper.h"
@@ -85,6 +87,10 @@
bool doNotWakeByDefault{};
} mParameters{};
+ // Store the value of enable wake for alphanumeric keyboard flag.
+ const bool mEnableAlphabeticKeyboardWakeFlag =
+ com::android::input::flags::enable_alphabetic_keyboard_wake();
+
KeyboardInputMapper(InputDeviceContext& deviceContext,
const InputReaderConfiguration& readerConfig, uint32_t source);
void configureParameters();
@@ -109,6 +115,8 @@
[[nodiscard]] std::list<NotifyArgs> cancelAllDownKeys(nsecs_t when);
void onKeyDownProcessed(nsecs_t downTime);
uint32_t getEventSource() const;
+
+ bool wakeOnAlphabeticKeyboard(const KeyboardType keyboardType) const;
};
} // namespace android
diff --git a/services/inputflinger/tests/CursorInputMapper_test.cpp b/services/inputflinger/tests/CursorInputMapper_test.cpp
index 1762a45..d4e8fdf 100644
--- a/services/inputflinger/tests/CursorInputMapper_test.cpp
+++ b/services/inputflinger/tests/CursorInputMapper_test.cpp
@@ -25,8 +25,10 @@
#include <android-base/logging.h>
#include <android_companion_virtualdevice_flags.h>
#include <com_android_input_flags.h>
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <input/DisplayViewport.h>
+#include <input/InputEventLabels.h>
#include <linux/input-event-codes.h>
#include <linux/input.h>
#include <utils/Timers.h>
@@ -52,6 +54,8 @@
constexpr auto BUTTON_RELEASE = AMOTION_EVENT_ACTION_BUTTON_RELEASE;
constexpr auto HOVER_MOVE = AMOTION_EVENT_ACTION_HOVER_MOVE;
constexpr auto INVALID_CURSOR_POSITION = AMOTION_EVENT_INVALID_CURSOR_POSITION;
+constexpr auto AXIS_X = AMOTION_EVENT_AXIS_X;
+constexpr auto AXIS_Y = AMOTION_EVENT_AXIS_Y;
constexpr ui::LogicalDisplayId DISPLAY_ID = ui::LogicalDisplayId::DEFAULT;
constexpr ui::LogicalDisplayId SECONDARY_DISPLAY_ID = ui::LogicalDisplayId{DISPLAY_ID.val() + 1};
constexpr int32_t DISPLAY_WIDTH = 480;
@@ -94,9 +98,35 @@
return v;
}
+// In a number of these tests, we want to check that some pointer motion is reported without
+// specifying an exact value, as that would require updating the tests every time the pointer
+// ballistics was changed. To do this, we make some matchers that only check the sign of a
+// particular axis.
+MATCHER_P(WithPositiveAxis, axis, "MotionEvent with a positive axis value") {
+ *result_listener << "expected 1 pointer with a positive "
+ << InputEventLookup::getAxisLabel(axis) << " axis but got "
+ << arg.pointerCoords.size() << " pointers, with axis value "
+ << arg.pointerCoords[0].getAxisValue(axis);
+ return arg.pointerCoords.size() == 1 && arg.pointerCoords[0].getAxisValue(axis) > 0;
+}
+
+MATCHER_P(WithZeroAxis, axis, "MotionEvent with a zero axis value") {
+ *result_listener << "expected 1 pointer with a zero " << InputEventLookup::getAxisLabel(axis)
+ << " axis but got " << arg.pointerCoords.size()
+ << " pointers, with axis value " << arg.pointerCoords[0].getAxisValue(axis);
+ return arg.pointerCoords.size() == 1 && arg.pointerCoords[0].getAxisValue(axis) == 0;
+}
+
+MATCHER_P(WithNegativeAxis, axis, "MotionEvent with a negative axis value") {
+ *result_listener << "expected 1 pointer with a negative "
+ << InputEventLookup::getAxisLabel(axis) << " axis but got "
+ << arg.pointerCoords.size() << " pointers, with axis value "
+ << arg.pointerCoords[0].getAxisValue(axis);
+ return arg.pointerCoords.size() == 1 && arg.pointerCoords[0].getAxisValue(axis) < 0;
+}
+
} // namespace
-namespace input_flags = com::android::input::flags;
namespace vd_flags = android::companion::virtualdevice::flags;
/**
@@ -150,24 +180,21 @@
ASSERT_GT(mDevice->getGeneration(), generation);
}
- void testMotionRotation(int32_t originalX, int32_t originalY, int32_t rotatedX,
- int32_t rotatedY) {
+ void testRotation(int32_t originalX, int32_t originalY,
+ const testing::Matcher<NotifyMotionArgs>& coordsMatcher) {
std::list<NotifyArgs> args;
args += process(ARBITRARY_TIME, EV_REL, REL_X, originalX);
args += process(ARBITRARY_TIME, EV_REL, REL_Y, originalY);
args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
ASSERT_THAT(args,
ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(ACTION_MOVE),
- WithCoords(float(rotatedX) / TRACKBALL_MOVEMENT_THRESHOLD,
- float(rotatedY) / TRACKBALL_MOVEMENT_THRESHOLD)))));
+ AllOf(WithMotionAction(ACTION_MOVE), coordsMatcher))));
}
};
class CursorInputMapperUnitTest : public CursorInputMapperUnitTestBase {
protected:
void SetUp() override {
- input_flags::enable_new_mouse_pointer_ballistics(false);
vd_flags::high_resolution_scroll(false);
CursorInputMapperUnitTestBase::SetUp();
}
@@ -344,14 +371,12 @@
args += process(EV_KEY, BTN_MOUSE, 0);
args += process(EV_SYN, SYN_REPORT, 0);
ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(BUTTON_RELEASE),
- WithSource(AINPUT_SOURCE_MOUSE_RELATIVE),
- WithCoords(0.0f, 0.0f), WithPressure(0.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(ACTION_UP),
- WithSource(AINPUT_SOURCE_MOUSE_RELATIVE),
- WithCoords(0.0f, 0.0f), WithPressure(0.0f)))));
+ ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_RELEASE)),
+ VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_UP))));
+ ASSERT_THAT(args,
+ Each(VariantWith<NotifyMotionArgs>(AllOf(WithSource(AINPUT_SOURCE_MOUSE_RELATIVE),
+ WithCoords(0.0f, 0.0f),
+ WithPressure(0.0f)))));
// Another move.
args.clear();
@@ -377,7 +402,8 @@
ElementsAre(VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE),
expectedCoords, expectedCursorPosition,
- WithRelativeMotion(10.0f, 20.0f)))));
+ WithPositiveAxis(AMOTION_EVENT_AXIS_RELATIVE_X),
+ WithPositiveAxis(AMOTION_EVENT_AXIS_RELATIVE_Y)))));
}
TEST_F(CursorInputMapperUnitTest, PopulateDeviceInfoReturnsScaledRangeInNavigationMode) {
@@ -411,64 +437,40 @@
args += process(ARBITRARY_TIME, EV_KEY, BTN_MOUSE, 1);
args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
EXPECT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithEventTime(ARBITRARY_TIME), WithDeviceId(DEVICE_ID),
- WithSource(AINPUT_SOURCE_TRACKBALL), WithFlags(0),
- WithEdgeFlags(0), WithPolicyFlags(0),
- WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
- WithMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON),
- WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY),
- WithPointerCount(1), WithPointerId(0, 0),
- WithToolType(ToolType::MOUSE), WithCoords(0.0f, 0.0f),
- WithPressure(1.0f),
- WithPrecision(TRACKBALL_MOVEMENT_THRESHOLD,
- TRACKBALL_MOVEMENT_THRESHOLD),
- WithDownTime(ARBITRARY_TIME))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithEventTime(ARBITRARY_TIME), WithDeviceId(DEVICE_ID),
- WithSource(AINPUT_SOURCE_TRACKBALL), WithFlags(0),
- WithEdgeFlags(0), WithPolicyFlags(0),
- WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
- WithMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON),
- WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY),
- WithPointerCount(1), WithPointerId(0, 0),
- WithToolType(ToolType::MOUSE), WithCoords(0.0f, 0.0f),
- WithPressure(1.0f),
- WithPrecision(TRACKBALL_MOVEMENT_THRESHOLD,
- TRACKBALL_MOVEMENT_THRESHOLD),
- WithDownTime(ARBITRARY_TIME)))));
+ ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_DOWN)),
+ VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_PRESS))));
+ EXPECT_THAT(args,
+ Each(VariantWith<NotifyMotionArgs>(
+ AllOf(WithEventTime(ARBITRARY_TIME), WithDeviceId(DEVICE_ID),
+ WithSource(AINPUT_SOURCE_TRACKBALL), WithFlags(0), WithEdgeFlags(0),
+ WithPolicyFlags(0),
+ WithMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON),
+ WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithPointerCount(1),
+ WithPointerId(0, 0), WithToolType(ToolType::MOUSE),
+ WithCoords(0.0f, 0.0f), WithPressure(1.0f),
+ WithPrecision(TRACKBALL_MOVEMENT_THRESHOLD,
+ TRACKBALL_MOVEMENT_THRESHOLD),
+ WithDownTime(ARBITRARY_TIME)))));
args.clear();
// Button release. Should have same down time.
args += process(ARBITRARY_TIME + 1, EV_KEY, BTN_MOUSE, 0);
args += process(ARBITRARY_TIME + 1, EV_SYN, SYN_REPORT, 0);
EXPECT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithEventTime(ARBITRARY_TIME + 1),
- WithDeviceId(DEVICE_ID),
- WithSource(AINPUT_SOURCE_TRACKBALL), WithFlags(0),
- WithEdgeFlags(0), WithPolicyFlags(0),
- WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
- WithMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON),
- WithButtonState(0), WithPointerCount(1),
- WithPointerId(0, 0), WithToolType(ToolType::MOUSE),
- WithCoords(0.0f, 0.0f), WithPressure(0.0f),
- WithPrecision(TRACKBALL_MOVEMENT_THRESHOLD,
- TRACKBALL_MOVEMENT_THRESHOLD),
- WithDownTime(ARBITRARY_TIME))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithEventTime(ARBITRARY_TIME + 1),
- WithDeviceId(DEVICE_ID),
- WithSource(AINPUT_SOURCE_TRACKBALL), WithFlags(0),
- WithEdgeFlags(0), WithPolicyFlags(0),
- WithMotionAction(AMOTION_EVENT_ACTION_UP),
- WithMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON),
- WithButtonState(0), WithPointerCount(1),
- WithPointerId(0, 0), WithToolType(ToolType::MOUSE),
- WithCoords(0.0f, 0.0f), WithPressure(0.0f),
- WithPrecision(TRACKBALL_MOVEMENT_THRESHOLD,
- TRACKBALL_MOVEMENT_THRESHOLD),
- WithDownTime(ARBITRARY_TIME)))));
+ ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_RELEASE)),
+ VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_UP))));
+ EXPECT_THAT(args,
+ Each(VariantWith<NotifyMotionArgs>(
+ AllOf(WithEventTime(ARBITRARY_TIME + 1), WithDeviceId(DEVICE_ID),
+ WithSource(AINPUT_SOURCE_TRACKBALL), WithFlags(0), WithEdgeFlags(0),
+ WithPolicyFlags(0),
+ WithMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON),
+ WithButtonState(0), WithPointerCount(1), WithPointerId(0, 0),
+ WithToolType(ToolType::MOUSE), WithCoords(0.0f, 0.0f),
+ WithPressure(0.0f),
+ WithPrecision(TRACKBALL_MOVEMENT_THRESHOLD,
+ TRACKBALL_MOVEMENT_THRESHOLD),
+ WithDownTime(ARBITRARY_TIME)))));
}
TEST_F(CursorInputMapperUnitTest, ProcessShouldHandleIndependentXYUpdates) {
@@ -482,9 +484,8 @@
args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
EXPECT_THAT(args,
ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
- WithCoords(1.0f / TRACKBALL_MOVEMENT_THRESHOLD, 0.0f),
- WithPressure(0.0f)))));
+ AllOf(WithMotionAction(ACTION_MOVE), WithPressure(0.0f),
+ WithPositiveAxis(AXIS_X), WithZeroAxis(AXIS_Y)))));
args.clear();
// Motion in Y but not X.
@@ -492,9 +493,8 @@
args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
EXPECT_THAT(args,
ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
- WithCoords(0.0f, -2.0f / TRACKBALL_MOVEMENT_THRESHOLD),
- WithPressure(0.0f)))));
+ AllOf(WithMotionAction(ACTION_MOVE), WithPressure(0.0f),
+ WithZeroAxis(AXIS_X), WithNegativeAxis(AXIS_Y)))));
args.clear();
}
@@ -508,24 +508,22 @@
args += process(ARBITRARY_TIME, EV_KEY, BTN_MOUSE, 1);
args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
EXPECT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
- WithCoords(0.0f, 0.0f), WithPressure(1.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
- WithCoords(0.0f, 0.0f), WithPressure(1.0f)))));
+ ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_DOWN)),
+ VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_PRESS))));
+ EXPECT_THAT(args,
+ Each(VariantWith<NotifyMotionArgs>(
+ AllOf(WithCoords(0.0f, 0.0f), WithPressure(1.0f)))));
args.clear();
// Button release.
args += process(ARBITRARY_TIME, EV_KEY, BTN_MOUSE, 0);
args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
EXPECT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
- WithCoords(0.0f, 0.0f), WithPressure(0.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
- WithCoords(0.0f, 0.0f), WithPressure(0.0f)))));
+ ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_RELEASE)),
+ VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_UP))));
+ EXPECT_THAT(args,
+ Each(VariantWith<NotifyMotionArgs>(
+ AllOf(WithCoords(0.0f, 0.0f), WithPressure(0.0f)))));
}
TEST_F(CursorInputMapperUnitTest, ProcessShouldHandleCombinedXYAndButtonUpdates) {
@@ -540,16 +538,12 @@
args += process(ARBITRARY_TIME, EV_KEY, BTN_MOUSE, 1);
args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
EXPECT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
- WithCoords(1.0f / TRACKBALL_MOVEMENT_THRESHOLD,
- -2.0f / TRACKBALL_MOVEMENT_THRESHOLD),
- WithPressure(1.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
- WithCoords(1.0f / TRACKBALL_MOVEMENT_THRESHOLD,
- -2.0f / TRACKBALL_MOVEMENT_THRESHOLD),
- WithPressure(1.0f)))));
+ ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_DOWN)),
+ VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_PRESS))));
+ EXPECT_THAT(args,
+ Each(VariantWith<NotifyMotionArgs>(AllOf(WithPositiveAxis(AXIS_X),
+ WithNegativeAxis(AXIS_Y),
+ WithPressure(1.0f)))));
args.clear();
// Move X, Y a bit while pressed.
@@ -558,22 +552,19 @@
args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
EXPECT_THAT(args,
ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
- WithCoords(2.0f / TRACKBALL_MOVEMENT_THRESHOLD,
- 1.0f / TRACKBALL_MOVEMENT_THRESHOLD),
- WithPressure(1.0f)))));
+ AllOf(WithMotionAction(ACTION_MOVE), WithPressure(1.0f),
+ WithPositiveAxis(AXIS_X), WithPositiveAxis(AXIS_Y)))));
args.clear();
// Release Button.
args += process(ARBITRARY_TIME, EV_KEY, BTN_MOUSE, 0);
args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
EXPECT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
- WithCoords(0.0f, 0.0f), WithPressure(0.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
- WithCoords(0.0f, 0.0f), WithPressure(0.0f)))));
+ ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_RELEASE)),
+ VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_UP))));
+ EXPECT_THAT(args,
+ Each(VariantWith<NotifyMotionArgs>(
+ AllOf(WithCoords(0.0f, 0.0f), WithPressure(0.0f)))));
args.clear();
}
@@ -586,14 +577,16 @@
.WillRepeatedly(Return(createPrimaryViewport(ui::Rotation::Rotation90)));
mMapper = createInputMapper<CursorInputMapper>(*mDeviceContext, mReaderConfiguration);
- ASSERT_NO_FATAL_FAILURE(testMotionRotation( 0, 1, 0, 1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, 1, 1, 1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, 0, 1, 0));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, -1, 1, -1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation( 0, -1, 0, -1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, -1, -1, -1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 0, -1, 0));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 1, -1, 1));
+ constexpr auto X = AXIS_X;
+ constexpr auto Y = AXIS_Y;
+ ASSERT_NO_FATAL_FAILURE(testRotation( 0, 1, AllOf(WithZeroAxis(X), WithPositiveAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation( 1, 1, AllOf(WithPositiveAxis(X), WithPositiveAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation( 1, 0, AllOf(WithPositiveAxis(X), WithZeroAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation( 1, -1, AllOf(WithPositiveAxis(X), WithNegativeAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation( 0, -1, AllOf(WithZeroAxis(X), WithNegativeAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation(-1, -1, AllOf(WithNegativeAxis(X), WithNegativeAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation(-1, 0, AllOf(WithNegativeAxis(X), WithZeroAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation(-1, 1, AllOf(WithNegativeAxis(X), WithPositiveAxis(Y))));
}
TEST_F(CursorInputMapperUnitTest, ProcessShouldRotateMotionsWhenNotOrientationAware) {
@@ -604,54 +597,56 @@
.WillRepeatedly(Return(createPrimaryViewport(ui::Rotation::Rotation0)));
mMapper = createInputMapper<CursorInputMapper>(*mDeviceContext, mReaderConfiguration);
- ASSERT_NO_FATAL_FAILURE(testMotionRotation( 0, 1, 0, 1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, 1, 1, 1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, 0, 1, 0));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, -1, 1, -1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation( 0, -1, 0, -1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, -1, -1, -1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 0, -1, 0));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 1, -1, 1));
+ constexpr auto X = AXIS_X;
+ constexpr auto Y = AXIS_Y;
+ ASSERT_NO_FATAL_FAILURE(testRotation( 0, 1, AllOf(WithZeroAxis(X), WithPositiveAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation( 1, 1, AllOf(WithPositiveAxis(X), WithPositiveAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation( 1, 0, AllOf(WithPositiveAxis(X), WithZeroAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation( 1, -1, AllOf(WithPositiveAxis(X), WithNegativeAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation( 0, -1, AllOf(WithZeroAxis(X), WithNegativeAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation(-1, -1, AllOf(WithNegativeAxis(X), WithNegativeAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation(-1, 0, AllOf(WithNegativeAxis(X), WithZeroAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation(-1, 1, AllOf(WithNegativeAxis(X), WithPositiveAxis(Y))));
EXPECT_CALL((*mDevice), getAssociatedViewport)
.WillRepeatedly(Return(createPrimaryViewport(ui::Rotation::Rotation90)));
std::list<NotifyArgs> args =
mMapper->reconfigure(ARBITRARY_TIME, mReaderConfiguration,
InputReaderConfiguration::Change::DISPLAY_INFO);
- ASSERT_NO_FATAL_FAILURE(testMotionRotation( 0, 1, -1, 0));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, 1, -1, 1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, 0, 0, 1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, -1, 1, 1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation( 0, -1, 1, 0));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, -1, 1, -1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 0, 0, -1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 1, -1, -1));
+ ASSERT_NO_FATAL_FAILURE(testRotation( 0, 1, AllOf(WithNegativeAxis(X), WithZeroAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation( 1, 1, AllOf(WithNegativeAxis(X), WithPositiveAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation( 1, 0, AllOf(WithZeroAxis(X), WithPositiveAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation( 1, -1, AllOf(WithPositiveAxis(X), WithPositiveAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation( 0, -1, AllOf(WithPositiveAxis(X), WithZeroAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation(-1, -1, AllOf(WithPositiveAxis(X), WithNegativeAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation(-1, 0, AllOf(WithZeroAxis(X), WithNegativeAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation(-1, 1, AllOf(WithNegativeAxis(X), WithNegativeAxis(Y))));
EXPECT_CALL((*mDevice), getAssociatedViewport)
.WillRepeatedly(Return(createPrimaryViewport(ui::Rotation::Rotation180)));
args = mMapper->reconfigure(ARBITRARY_TIME, mReaderConfiguration,
InputReaderConfiguration::Change::DISPLAY_INFO);
- ASSERT_NO_FATAL_FAILURE(testMotionRotation( 0, 1, 0, -1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, 1, -1, -1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, 0, -1, 0));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, -1, -1, 1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation( 0, -1, 0, 1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, -1, 1, 1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 0, 1, 0));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 1, 1, -1));
+ ASSERT_NO_FATAL_FAILURE(testRotation( 0, 1, AllOf(WithZeroAxis(X), WithNegativeAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation( 1, 1, AllOf(WithNegativeAxis(X), WithNegativeAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation( 1, 0, AllOf(WithNegativeAxis(X), WithZeroAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation( 1, -1, AllOf(WithNegativeAxis(X), WithPositiveAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation( 0, -1, AllOf(WithZeroAxis(X), WithPositiveAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation(-1, -1, AllOf(WithPositiveAxis(X), WithPositiveAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation(-1, 0, AllOf(WithPositiveAxis(X), WithZeroAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation(-1, 1, AllOf(WithPositiveAxis(X), WithNegativeAxis(Y))));
EXPECT_CALL((*mDevice), getAssociatedViewport)
.WillRepeatedly(Return(createPrimaryViewport(ui::Rotation::Rotation270)));
args = mMapper->reconfigure(ARBITRARY_TIME, mReaderConfiguration,
InputReaderConfiguration::Change::DISPLAY_INFO);
- ASSERT_NO_FATAL_FAILURE(testMotionRotation( 0, 1, 1, 0));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, 1, 1, -1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, 0, 0, -1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, -1, -1, -1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation( 0, -1, -1, 0));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, -1, -1, 1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 0, 0, 1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 1, 1, 1));
+ ASSERT_NO_FATAL_FAILURE(testRotation( 0, 1, AllOf(WithPositiveAxis(X), WithZeroAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation( 1, 1, AllOf(WithPositiveAxis(X), WithNegativeAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation( 1, 0, AllOf(WithZeroAxis(X), WithNegativeAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation( 1, -1, AllOf(WithNegativeAxis(X), WithNegativeAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation( 0, -1, AllOf(WithNegativeAxis(X), WithZeroAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation(-1, -1, AllOf(WithNegativeAxis(X), WithPositiveAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation(-1, 0, AllOf(WithZeroAxis(X), WithPositiveAxis(Y))));
+ ASSERT_NO_FATAL_FAILURE(testRotation(-1, 1, AllOf(WithPositiveAxis(X), WithPositiveAxis(Y))));
}
TEST_F(CursorInputMapperUnitTest, PopulateDeviceInfoReturnsRangeFromPolicy) {
@@ -742,30 +737,22 @@
args += process(ARBITRARY_TIME, EV_KEY, BTN_LEFT, 1);
args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
EXPECT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
- WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY),
- WithCoords(0.0f, 0.0f), WithPressure(1.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
- WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY),
- WithCoords(0.0f, 0.0f), WithPressure(1.0f)))));
+ ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_DOWN)),
+ VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_PRESS))));
+ EXPECT_THAT(args,
+ Each(VariantWith<NotifyMotionArgs>(
+ AllOf(WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithCoords(0.0f, 0.0f),
+ WithPressure(1.0f)))));
args.clear();
args += process(ARBITRARY_TIME, EV_KEY, BTN_LEFT, 0);
args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
EXPECT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
- WithButtonState(0), WithCoords(0.0f, 0.0f),
- WithPressure(0.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
- WithButtonState(0), WithCoords(0.0f, 0.0f),
- WithPressure(0.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
- WithButtonState(0), WithCoords(0.0f, 0.0f),
- WithPressure(0.0f)))));
+ ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_RELEASE)),
+ VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_UP)),
+ VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_MOVE))));
+ EXPECT_THAT(args,
+ Each(VariantWith<NotifyMotionArgs>(
+ AllOf(WithButtonState(0), WithCoords(0.0f, 0.0f), WithPressure(0.0f)))));
args.clear();
// press BTN_RIGHT + BTN_MIDDLE, release BTN_RIGHT, release BTN_MIDDLE
@@ -774,49 +761,41 @@
args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
EXPECT_THAT(args,
ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
+ AllOf(WithMotionAction(ACTION_DOWN),
WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY |
- AMOTION_EVENT_BUTTON_TERTIARY),
- WithCoords(0.0f, 0.0f), WithPressure(1.0f))),
+ AMOTION_EVENT_BUTTON_TERTIARY))),
VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
- WithButtonState(AMOTION_EVENT_BUTTON_TERTIARY),
- WithCoords(0.0f, 0.0f), WithPressure(1.0f))),
+ AllOf(WithMotionAction(BUTTON_PRESS),
+ WithButtonState(AMOTION_EVENT_BUTTON_TERTIARY))),
VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
+ AllOf(WithMotionAction(BUTTON_PRESS),
WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY |
- AMOTION_EVENT_BUTTON_TERTIARY),
- WithCoords(0.0f, 0.0f), WithPressure(1.0f)))));
+ AMOTION_EVENT_BUTTON_TERTIARY)))));
+ EXPECT_THAT(args,
+ Each(VariantWith<NotifyMotionArgs>(
+ AllOf(WithCoords(0.0f, 0.0f), WithPressure(1.0f)))));
args.clear();
args += process(ARBITRARY_TIME, EV_KEY, BTN_RIGHT, 0);
args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
EXPECT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
- WithButtonState(AMOTION_EVENT_BUTTON_TERTIARY),
- WithCoords(0.0f, 0.0f), WithPressure(1.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
- WithButtonState(AMOTION_EVENT_BUTTON_TERTIARY),
- WithCoords(0.0f, 0.0f), WithPressure(1.0f)))));
+ ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_RELEASE)),
+ VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_MOVE))));
+ EXPECT_THAT(args,
+ Each(VariantWith<NotifyMotionArgs>(
+ AllOf(WithButtonState(AMOTION_EVENT_BUTTON_TERTIARY),
+ WithCoords(0.0f, 0.0f), WithPressure(1.0f)))));
args.clear();
args += process(ARBITRARY_TIME, EV_KEY, BTN_MIDDLE, 0);
args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
EXPECT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
- WithButtonState(0), WithCoords(0.0f, 0.0f),
- WithPressure(0.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithButtonState(0),
- WithMotionAction(AMOTION_EVENT_ACTION_UP),
- WithCoords(0.0f, 0.0f), WithPressure(0.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithButtonState(0),
- WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
- WithCoords(0.0f, 0.0f), WithPressure(0.0f)))));
+ ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_RELEASE)),
+ VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_UP)),
+ VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_MOVE))));
+ EXPECT_THAT(args,
+ Each(VariantWith<NotifyMotionArgs>(
+ AllOf(WithButtonState(0), WithCoords(0.0f, 0.0f), WithPressure(0.0f)))));
}
class CursorInputMapperButtonKeyTest
@@ -838,11 +817,11 @@
ElementsAre(VariantWith<NotifyKeyArgs>(AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN),
WithKeyCode(expectedKeyCode))),
VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
+ AllOf(WithMotionAction(HOVER_MOVE),
WithButtonState(expectedButtonState),
WithCoords(0.0f, 0.0f), WithPressure(0.0f))),
VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
+ AllOf(WithMotionAction(BUTTON_PRESS),
WithButtonState(expectedButtonState),
WithCoords(0.0f, 0.0f), WithPressure(0.0f)))));
args.clear();
@@ -851,13 +830,11 @@
args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
EXPECT_THAT(args,
ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
- WithButtonState(0), WithCoords(0.0f, 0.0f),
- WithPressure(0.0f))),
+ AllOf(WithMotionAction(BUTTON_RELEASE), WithButtonState(0),
+ WithCoords(0.0f, 0.0f), WithPressure(0.0f))),
VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
- WithButtonState(0), WithCoords(0.0f, 0.0f),
- WithPressure(0.0f))),
+ AllOf(WithMotionAction(HOVER_MOVE), WithButtonState(0),
+ WithCoords(0.0f, 0.0f), WithPressure(0.0f))),
VariantWith<NotifyKeyArgs>(AllOf(WithKeyAction(AKEY_EVENT_ACTION_UP),
WithKeyCode(expectedKeyCode)))));
}
@@ -881,8 +858,7 @@
args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
EXPECT_THAT(args,
ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithSource(AINPUT_SOURCE_MOUSE),
- WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
+ AllOf(WithSource(AINPUT_SOURCE_MOUSE), WithMotionAction(HOVER_MOVE),
WithCoords(0.0f, 0.0f), WithPressure(0.0f), WithSize(0.0f),
WithTouchDimensions(0.0f, 0.0f), WithToolDimensions(0.0f, 0.0f),
WithOrientation(0.0f), WithDistance(0.0f)))));
@@ -897,13 +873,11 @@
args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
EXPECT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithSource(AINPUT_SOURCE_MOUSE),
- WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE))),
+ ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_MOVE)),
VariantWith<NotifyMotionArgs>(
- AllOf(WithSource(AINPUT_SOURCE_MOUSE),
- WithMotionAction(AMOTION_EVENT_ACTION_SCROLL),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_SCROLL),
WithScroll(1.0f, 1.0f)))));
+ EXPECT_THAT(args, Each(VariantWith<NotifyMotionArgs>(WithSource(AINPUT_SOURCE_MOUSE))));
}
TEST_F(CursorInputMapperUnitTest, ProcessHighResScroll) {
@@ -920,13 +894,11 @@
args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
EXPECT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithSource(AINPUT_SOURCE_MOUSE),
- WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE))),
+ ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_MOVE)),
VariantWith<NotifyMotionArgs>(
- AllOf(WithSource(AINPUT_SOURCE_MOUSE),
- WithMotionAction(AMOTION_EVENT_ACTION_SCROLL),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_SCROLL),
WithScroll(0.5f, 0.5f)))));
+ EXPECT_THAT(args, Each(VariantWith<NotifyMotionArgs>(WithSource(AINPUT_SOURCE_MOUSE))));
}
TEST_F(CursorInputMapperUnitTest, HighResScrollIgnoresRegularScroll) {
@@ -945,13 +917,11 @@
args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
EXPECT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithSource(AINPUT_SOURCE_MOUSE),
- WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE))),
+ ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_MOVE)),
VariantWith<NotifyMotionArgs>(
- AllOf(WithSource(AINPUT_SOURCE_MOUSE),
- WithMotionAction(AMOTION_EVENT_ACTION_SCROLL),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_SCROLL),
WithScroll(0.5f, 0.5f)))));
+ EXPECT_THAT(args, Each(VariantWith<NotifyMotionArgs>(WithSource(AINPUT_SOURCE_MOUSE))));
}
TEST_F(CursorInputMapperUnitTest, ProcessReversedVerticalScroll) {
@@ -966,13 +936,11 @@
// Reversed vertical scrolling only affects the y-axis, expect it to be -1.0f to indicate the
// inverted scroll direction.
EXPECT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithSource(AINPUT_SOURCE_MOUSE),
- WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE))),
+ ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_MOVE)),
VariantWith<NotifyMotionArgs>(
- AllOf(WithSource(AINPUT_SOURCE_MOUSE),
- WithMotionAction(AMOTION_EVENT_ACTION_SCROLL),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_SCROLL),
WithScroll(1.0f, -1.0f)))));
+ EXPECT_THAT(args, Each(VariantWith<NotifyMotionArgs>(WithSource(AINPUT_SOURCE_MOUSE))));
}
TEST_F(CursorInputMapperUnitTest, ProcessHighResReversedVerticalScroll) {
@@ -990,13 +958,11 @@
args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
EXPECT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithSource(AINPUT_SOURCE_MOUSE),
- WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE))),
+ ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_MOVE)),
VariantWith<NotifyMotionArgs>(
- AllOf(WithSource(AINPUT_SOURCE_MOUSE),
- WithMotionAction(AMOTION_EVENT_ACTION_SCROLL),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_SCROLL),
WithScroll(0.5f, -0.5f)))));
+ EXPECT_THAT(args, Each(VariantWith<NotifyMotionArgs>(WithSource(AINPUT_SOURCE_MOUSE))));
}
/**
@@ -1005,10 +971,6 @@
*/
TEST_F(CursorInputMapperUnitTest, PointerCaptureDisablesVelocityProcessing) {
mPropertyMap.addProperty("cursor.mode", "pointer");
- const VelocityControlParameters testParams(/*scale=*/5.f, /*lowThreshold=*/0.f,
- /*highThreshold=*/100.f, /*acceleration=*/10.f);
- mReaderConfiguration.pointerVelocityControlParameters = testParams;
- mFakePolicy->setVelocityControlParams(testParams);
createMapper();
NotifyMotionArgs motionArgs;
@@ -1020,8 +982,7 @@
args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
EXPECT_THAT(args,
ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithSource(AINPUT_SOURCE_MOUSE),
- WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE)))));
+ AllOf(WithSource(AINPUT_SOURCE_MOUSE), WithMotionAction(HOVER_MOVE)))));
motionArgs = std::get<NotifyMotionArgs>(args.front());
const float relX = motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
const float relY = motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
@@ -1039,12 +1000,7 @@
EXPECT_THAT(args,
ElementsAre(VariantWith<NotifyMotionArgs>(
AllOf(WithSource(AINPUT_SOURCE_MOUSE_RELATIVE),
- WithMotionAction(AMOTION_EVENT_ACTION_MOVE)))));
- motionArgs = std::get<NotifyMotionArgs>(args.front());
- const float relX2 = motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
- const float relY2 = motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
- ASSERT_EQ(10, relX2);
- ASSERT_EQ(20, relY2);
+ WithMotionAction(ACTION_MOVE), WithRelativeMotion(10, 20)))));
}
TEST_F(CursorInputMapperUnitTest, ConfigureDisplayIdNoAssociatedViewport) {
@@ -1067,54 +1023,12 @@
args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
EXPECT_THAT(args,
ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
- WithSource(AINPUT_SOURCE_MOUSE),
+ AllOf(WithMotionAction(HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE),
WithDisplayId(ui::LogicalDisplayId::INVALID),
WithCoords(0.0f, 0.0f)))));
}
-// TODO(b/320433834): De-duplicate the test cases once the flag is removed.
-class CursorInputMapperUnitTestWithNewBallistics : public CursorInputMapperUnitTestBase {
-protected:
- void SetUp() override {
- input_flags::enable_new_mouse_pointer_ballistics(true);
- CursorInputMapperUnitTestBase::SetUp();
- }
-};
-
-TEST_F(CursorInputMapperUnitTestWithNewBallistics, PointerCaptureDisablesVelocityProcessing) {
- mPropertyMap.addProperty("cursor.mode", "pointer");
- createMapper();
-
- NotifyMotionArgs motionArgs;
- std::list<NotifyArgs> args;
-
- // Move and verify scale is applied.
- args += process(ARBITRARY_TIME, EV_REL, REL_X, 10);
- args += process(ARBITRARY_TIME, EV_REL, REL_Y, 20);
- args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
- motionArgs = std::get<NotifyMotionArgs>(args.front());
- const float relX = motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
- const float relY = motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
- ASSERT_GT(relX, 10);
- ASSERT_GT(relY, 20);
- args.clear();
-
- // Enable Pointer Capture
- setPointerCapture(true);
-
- // Move and verify scale is not applied.
- args += process(ARBITRARY_TIME, EV_REL, REL_X, 10);
- args += process(ARBITRARY_TIME, EV_REL, REL_Y, 20);
- args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
- motionArgs = std::get<NotifyMotionArgs>(args.front());
- const float relX2 = motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
- const float relY2 = motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
- ASSERT_EQ(10, relX2);
- ASSERT_EQ(20, relY2);
-}
-
-TEST_F(CursorInputMapperUnitTestWithNewBallistics, ConfigureAccelerationWithAssociatedViewport) {
+TEST_F(CursorInputMapperUnitTest, ConfigureAccelerationWithAssociatedViewport) {
mPropertyMap.addProperty("cursor.mode", "pointer");
DisplayViewport primaryViewport = createPrimaryViewport(ui::Rotation::Rotation0);
mReaderConfiguration.setDisplayViewports({primaryViewport});
@@ -1149,7 +1063,7 @@
WithRelativeMotion(10, 20)))));
}
-TEST_F(CursorInputMapperUnitTestWithNewBallistics, ConfigureAccelerationOnDisplayChange) {
+TEST_F(CursorInputMapperUnitTest, ConfigureAccelerationOnDisplayChange) {
mPropertyMap.addProperty("cursor.mode", "pointer");
DisplayViewport primaryViewport = createPrimaryViewport(ui::Rotation::Rotation0);
mReaderConfiguration.setDisplayViewports({primaryViewport});
@@ -1186,72 +1100,6 @@
WithRelativeMotion(10, 20)))));
}
-TEST_F(CursorInputMapperUnitTestWithNewBallistics, ProcessRegularScroll) {
- createMapper();
-
- std::list<NotifyArgs> args;
- args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, 1);
- args += process(ARBITRARY_TIME, EV_REL, REL_HWHEEL, 1);
- args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
-
- EXPECT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithSource(AINPUT_SOURCE_MOUSE),
- WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithSource(AINPUT_SOURCE_MOUSE),
- WithMotionAction(AMOTION_EVENT_ACTION_SCROLL),
- WithScroll(1.0f, 1.0f)))));
-}
-
-TEST_F(CursorInputMapperUnitTestWithNewBallistics, ProcessHighResScroll) {
- vd_flags::high_resolution_scroll(true);
- EXPECT_CALL(mMockEventHub, hasRelativeAxis(EVENTHUB_ID, REL_WHEEL_HI_RES))
- .WillRepeatedly(Return(true));
- EXPECT_CALL(mMockEventHub, hasRelativeAxis(EVENTHUB_ID, REL_HWHEEL_HI_RES))
- .WillRepeatedly(Return(true));
- createMapper();
-
- std::list<NotifyArgs> args;
- args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL_HI_RES, 60);
- args += process(ARBITRARY_TIME, EV_REL, REL_HWHEEL_HI_RES, 60);
- args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
-
- EXPECT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithSource(AINPUT_SOURCE_MOUSE),
- WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithSource(AINPUT_SOURCE_MOUSE),
- WithMotionAction(AMOTION_EVENT_ACTION_SCROLL),
- WithScroll(0.5f, 0.5f)))));
-}
-
-TEST_F(CursorInputMapperUnitTestWithNewBallistics, HighResScrollIgnoresRegularScroll) {
- vd_flags::high_resolution_scroll(true);
- EXPECT_CALL(mMockEventHub, hasRelativeAxis(EVENTHUB_ID, REL_WHEEL_HI_RES))
- .WillRepeatedly(Return(true));
- EXPECT_CALL(mMockEventHub, hasRelativeAxis(EVENTHUB_ID, REL_HWHEEL_HI_RES))
- .WillRepeatedly(Return(true));
- createMapper();
-
- std::list<NotifyArgs> args;
- args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL_HI_RES, 60);
- args += process(ARBITRARY_TIME, EV_REL, REL_HWHEEL_HI_RES, 60);
- args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, 1);
- args += process(ARBITRARY_TIME, EV_REL, REL_HWHEEL, 1);
- args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
-
- EXPECT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithSource(AINPUT_SOURCE_MOUSE),
- WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithSource(AINPUT_SOURCE_MOUSE),
- WithMotionAction(AMOTION_EVENT_ACTION_SCROLL),
- WithScroll(0.5f, 0.5f)))));
-}
-
namespace {
// Minimum timestamp separation between subsequent input events from a Bluetooth device.
@@ -1279,8 +1127,7 @@
argsList += process(kernelEventTime, EV_SYN, SYN_REPORT, 0);
EXPECT_THAT(argsList,
ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
- WithEventTime(expectedEventTime)))));
+ AllOf(WithMotionAction(HOVER_MOVE), WithEventTime(expectedEventTime)))));
argsList.clear();
// Process several events that come in quick succession, according to their timestamps.
@@ -1294,7 +1141,7 @@
argsList += process(kernelEventTime, EV_SYN, SYN_REPORT, 0);
EXPECT_THAT(argsList,
ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
+ AllOf(WithMotionAction(HOVER_MOVE),
WithEventTime(expectedEventTime)))));
argsList.clear();
}
@@ -1310,8 +1157,7 @@
argsList += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
EXPECT_THAT(argsList,
ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
- WithEventTime(expectedEventTime)))));
+ AllOf(WithMotionAction(HOVER_MOVE), WithEventTime(expectedEventTime)))));
argsList.clear();
// Process several events with the same timestamp from the kernel.
@@ -1325,7 +1171,7 @@
argsList += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
EXPECT_THAT(argsList,
ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
+ AllOf(WithMotionAction(HOVER_MOVE),
WithEventTime(expectedEventTime)))));
argsList.clear();
}
@@ -1338,8 +1184,7 @@
argsList += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
EXPECT_THAT(argsList,
ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
- WithEventTime(cappedEventTime)))));
+ AllOf(WithMotionAction(HOVER_MOVE), WithEventTime(cappedEventTime)))));
argsList.clear();
}
}
@@ -1355,8 +1200,7 @@
argsList += process(kernelEventTime, EV_SYN, SYN_REPORT, 0);
EXPECT_THAT(argsList,
ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
- WithEventTime(expectedEventTime)))));
+ AllOf(WithMotionAction(HOVER_MOVE), WithEventTime(expectedEventTime)))));
argsList.clear();
// If the next event has a timestamp that is sufficiently spaced out so that Bluetooth timestamp
@@ -1368,8 +1212,7 @@
argsList += process(kernelEventTime, EV_SYN, SYN_REPORT, 0);
EXPECT_THAT(argsList,
ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
- WithEventTime(expectedEventTime)))));
+ AllOf(WithMotionAction(HOVER_MOVE), WithEventTime(expectedEventTime)))));
argsList.clear();
}
diff --git a/services/inputflinger/tests/FakeEventHub.cpp b/services/inputflinger/tests/FakeEventHub.cpp
index 943de6e..e72c440 100644
--- a/services/inputflinger/tests/FakeEventHub.cpp
+++ b/services/inputflinger/tests/FakeEventHub.cpp
@@ -650,4 +650,25 @@
}
}
+bool FakeEventHub::setKernelWakeEnabled(int32_t deviceId, bool enabled) {
+ Device* device = getDevice(deviceId);
+ if (device == nullptr) {
+ return false;
+ }
+ mKernelWakeup.emplace(deviceId, enabled);
+ return true;
+}
+
+bool FakeEventHub::fakeReadKernelWakeup(int32_t deviceId) const {
+ Device* device = getDevice(deviceId);
+ if (device == nullptr) {
+ return false;
+ }
+ auto it = mKernelWakeup.find(deviceId);
+ if (it == mKernelWakeup.end()) {
+ return false;
+ }
+ return it->second;
+}
+
} // namespace android
diff --git a/services/inputflinger/tests/FakeEventHub.h b/services/inputflinger/tests/FakeEventHub.h
index 2dfbb23..143b93b 100644
--- a/services/inputflinger/tests/FakeEventHub.h
+++ b/services/inputflinger/tests/FakeEventHub.h
@@ -94,6 +94,8 @@
// Simulates a device light intensities, from light id to light intensities map.
std::unordered_map<int32_t /* lightId */, std::unordered_map<LightColor, int32_t>>
mLightIntensities;
+ // fake sysfs node path and value.
+ std::unordered_map<int32_t /*deviceId*/, bool /* wakeupNode*/> mKernelWakeup;
public:
static constexpr int32_t DEFAULT_BATTERY = 1;
@@ -158,6 +160,8 @@
void setMtSlotValues(int32_t deviceId, int32_t axis, const std::vector<int32_t>& values);
base::Result<std::vector<int32_t>> getMtSlotValues(int32_t deviceId, int32_t axis,
size_t slotCount) const override;
+ bool setKernelWakeEnabled(int32_t deviceId, bool enabled) override;
+ bool fakeReadKernelWakeup(int32_t deviceId) const;
private:
Device* getDevice(int32_t deviceId) const;
diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.cpp b/services/inputflinger/tests/FakeInputReaderPolicy.cpp
index f373cac..7c5f350 100644
--- a/services/inputflinger/tests/FakeInputReaderPolicy.cpp
+++ b/services/inputflinger/tests/FakeInputReaderPolicy.cpp
@@ -217,7 +217,6 @@
}
void FakeInputReaderPolicy::setVelocityControlParams(const VelocityControlParameters& params) {
- mConfig.pointerVelocityControlParameters = params;
mConfig.wheelVelocityControlParameters = params;
}
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 6c8b65c..18469e0 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -36,6 +36,7 @@
#include <UinputDevice.h>
#include <android-base/thread_annotations.h>
#include <com_android_input_flags.h>
+#include <flag_macros.h>
#include <ftl/enum.h>
#include <gtest/gtest.h>
#include <ui/Rotation.h>
@@ -1392,6 +1393,20 @@
ASSERT_EQ(mReader->getLightColor(deviceId, /*lightId=*/1), LIGHT_BRIGHTNESS);
}
+TEST_F(InputReaderTest, SetPowerWakeUp) {
+ ASSERT_NO_FATAL_FAILURE(addDevice(1, "1st", InputDeviceClass::KEYBOARD, nullptr));
+ ASSERT_NO_FATAL_FAILURE(addDevice(2, "2nd", InputDeviceClass::KEYBOARD, nullptr));
+ ASSERT_NO_FATAL_FAILURE(addDevice(3, "3rd", InputDeviceClass::KEYBOARD, nullptr));
+
+ ASSERT_EQ(mFakeEventHub->fakeReadKernelWakeup(1), false);
+
+ ASSERT_TRUE(mFakeEventHub->setKernelWakeEnabled(2, true));
+ ASSERT_EQ(mFakeEventHub->fakeReadKernelWakeup(2), true);
+
+ ASSERT_TRUE(mFakeEventHub->setKernelWakeEnabled(3, false));
+ ASSERT_EQ(mFakeEventHub->fakeReadKernelWakeup(3), false);
+}
+
// --- InputReaderIntegrationTest ---
// These tests create and interact with the InputReader only through its interface.
@@ -4005,6 +4020,44 @@
ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_KEEP_TOUCH_MODE, args.flags);
}
+TEST_F_WITH_FLAGS(KeyboardInputMapperTest, WakeBehavior_AlphabeticKeyboard,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
+ enable_alphabetic_keyboard_wake))) {
+ // For internal alphabetic devices, keys will trigger wake on key down.
+
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_A, 0, AKEYCODE_A, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_HOME, 0, AKEYCODE_HOME, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_PLAYPAUSE, 0, AKEYCODE_MEDIA_PLAY_PAUSE, 0);
+
+ KeyboardInputMapper& mapper =
+ constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
+
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_A, 1);
+ NotifyKeyArgs args;
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+ ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
+
+ process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_A, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+ ASSERT_EQ(uint32_t(0), args.policyFlags);
+
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_HOME, 1);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+ ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
+
+ process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_HOME, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+ ASSERT_EQ(uint32_t(0), args.policyFlags);
+
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_PLAYPAUSE, 1);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+ ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
+
+ process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_PLAYPAUSE, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+ ASSERT_EQ(uint32_t(0), args.policyFlags);
+}
+
/**
* When there is more than one KeyboardInputMapper for an InputDevice, each mapper should produce
* events that use the shared keyboard source across all mappers. This is to ensure that each
diff --git a/services/inputflinger/tests/InterfaceMocks.h b/services/inputflinger/tests/InterfaceMocks.h
index a43e4e4..25e2b45 100644
--- a/services/inputflinger/tests/InterfaceMocks.h
+++ b/services/inputflinger/tests/InterfaceMocks.h
@@ -180,6 +180,7 @@
MOCK_METHOD(status_t, enableDevice, (int32_t deviceId), (override));
MOCK_METHOD(status_t, disableDevice, (int32_t deviceId), (override));
MOCK_METHOD(void, sysfsNodeChanged, (const std::string& sysfsNodePath), (override));
+ MOCK_METHOD(bool, setKernelWakeEnabled, (int32_t deviceId, bool enabled), (override));
};
class MockPointerChoreographerPolicyInterface : public PointerChoreographerPolicyInterface {
diff --git a/services/inputflinger/tests/KeyboardInputMapper_test.cpp b/services/inputflinger/tests/KeyboardInputMapper_test.cpp
index 88c25d3..bcc6062 100644
--- a/services/inputflinger/tests/KeyboardInputMapper_test.cpp
+++ b/services/inputflinger/tests/KeyboardInputMapper_test.cpp
@@ -20,16 +20,19 @@
#include "InputMapperTest.h"
#include "InterfaceMocks.h"
+#include "TestEventMatchers.h"
#define TAG "KeyboardInputMapper_test"
namespace android {
using testing::_;
+using testing::AllOf;
using testing::Args;
using testing::DoAll;
using testing::Return;
using testing::SetArgPointee;
+using testing::VariantWith;
/**
* Unit tests for KeyboardInputMapper.
@@ -86,4 +89,24 @@
}
}
+TEST_F(KeyboardInputMapperUnitTest, RepeatEventsDiscarded) {
+ std::list<NotifyArgs> args;
+ args += process(ARBITRARY_TIME, EV_KEY, KEY_0, 1);
+ args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
+
+ args += process(ARBITRARY_TIME, EV_KEY, KEY_0, 2);
+ args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
+
+ args += process(ARBITRARY_TIME, EV_KEY, KEY_0, 0);
+ args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
+
+ EXPECT_THAT(args,
+ ElementsAre(VariantWith<NotifyKeyArgs>(AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN),
+ WithKeyCode(AKEYCODE_0),
+ WithScanCode(KEY_0))),
+ VariantWith<NotifyKeyArgs>(AllOf(WithKeyAction(AKEY_EVENT_ACTION_UP),
+ WithKeyCode(AKEYCODE_0),
+ WithScanCode(KEY_0)))));
+}
+
} // namespace android
diff --git a/services/inputflinger/tests/LatencyTracker_test.cpp b/services/inputflinger/tests/LatencyTracker_test.cpp
index 3f14c23..ca0f1e8 100644
--- a/services/inputflinger/tests/LatencyTracker_test.cpp
+++ b/services/inputflinger/tests/LatencyTracker_test.cpp
@@ -16,10 +16,14 @@
#include "../dispatcher/LatencyTracker.h"
#include "../InputDeviceMetricsSource.h"
+#include "NotifyArgsBuilders.h"
+#include "android/input.h"
+#include <android-base/logging.h>
#include <android-base/properties.h>
#include <binder/Binder.h>
#include <gtest/gtest.h>
+#include <input/PrintTools.h>
#include <inttypes.h>
#include <linux/input.h>
#include <log/log.h>
@@ -48,11 +52,44 @@
}
void setDefaultInputDeviceInfo(LatencyTracker& tracker) {
- InputDeviceInfo deviceInfo = generateTestDeviceInfo(
- /*vendorId=*/0, /*productId=*/0, DEVICE_ID);
+ InputDeviceInfo deviceInfo = generateTestDeviceInfo(/*vendorId=*/0, /*productId=*/0, DEVICE_ID);
tracker.setInputDevices({deviceInfo});
}
+const auto FIRST_TOUCH_POINTER = PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200);
+
+/**
+ * This is a convenience method for comparing timelines that also prints the difference between
+ * the two structures. This helps debugging when the timelines don't match.
+ * @param received the timeline that was actually received
+ * @param expected the timeline that we expected to receive
+ * @return true if the two timelines match, false otherwise.
+ */
+bool timelinesAreEqual(const InputEventTimeline& received, const InputEventTimeline& expected) {
+ LOG_IF(ERROR, expected.eventTime != received.eventTime)
+ << "Received timeline with eventTime=" << received.eventTime
+ << " instead of expected eventTime=" << expected.eventTime;
+ LOG_IF(ERROR, expected.readTime != received.readTime)
+ << "Received timeline with readTime=" << received.readTime
+ << " instead of expected readTime=" << expected.readTime;
+ LOG_IF(ERROR, expected.vendorId != received.vendorId)
+ << "Received timeline with vendorId=" << received.vendorId
+ << " instead of expected vendorId=" << expected.vendorId;
+ LOG_IF(ERROR, expected.productId != received.productId)
+ << "Received timeline with productId=" << received.productId
+ << " instead of expected productId=" << expected.productId;
+ LOG_IF(ERROR, expected.sources != received.sources)
+ << "Received timeline with sources=" << dumpSet(received.sources, ftl::enum_string)
+ << " instead of expected sources=" << dumpSet(expected.sources, ftl::enum_string);
+ LOG_IF(ERROR, expected.inputEventActionType != received.inputEventActionType)
+ << "Received timeline with inputEventActionType="
+ << ftl::enum_string(received.inputEventActionType)
+ << " instead of expected inputEventActionType="
+ << ftl::enum_string(expected.inputEventActionType);
+
+ return received == expected;
+}
+
} // namespace
const std::chrono::duration ANR_TIMEOUT = std::chrono::milliseconds(
@@ -64,15 +101,14 @@
/*eventTime=*/2,
/*readTime=*/3,
/*vendorId=*/0,
- /*productId=*/0,
- /*sources=*/{InputDeviceUsageSource::UNKNOWN},
+ /*productId=*/0, {InputDeviceUsageSource::TOUCHSCREEN},
/*inputEventActionType=*/InputEventActionType::UNKNOWN_INPUT_EVENT);
ConnectionTimeline expectedCT(/*deliveryTime=*/6, /*consumeTime=*/7, /*finishTime=*/8);
- std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline;
+ std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline{};
graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = 9;
graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = 10;
- expectedCT.setGraphicsTimeline(std::move(graphicsTimeline));
- t.connectionTimelines.emplace(sp<BBinder>::make(), std::move(expectedCT));
+ expectedCT.setGraphicsTimeline(graphicsTimeline);
+ t.connectionTimelines.emplace(sp<BBinder>::make(), expectedCT);
return t;
}
@@ -118,16 +154,19 @@
void LatencyTrackerTest::triggerEventReporting(nsecs_t lastEventTime) {
const nsecs_t triggerEventTime =
lastEventTime + std::chrono::nanoseconds(ANR_TIMEOUT).count() + 1;
- mTracker->trackListener(/*inputEventId=*/1, triggerEventTime,
- /*readTime=*/3, DEVICE_ID,
- /*sources=*/{InputDeviceUsageSource::UNKNOWN},
- AMOTION_EVENT_ACTION_CANCEL, InputEventType::MOTION);
+ mTracker->trackListener(MotionArgsBuilder(AMOTION_EVENT_ACTION_CANCEL,
+ AINPUT_SOURCE_TOUCHSCREEN, /*inputEventId=*/1)
+ .eventTime(triggerEventTime)
+ .readTime(3)
+ .deviceId(DEVICE_ID)
+ .pointer(FIRST_TOUCH_POINTER)
+ .build());
}
-void LatencyTrackerTest::assertReceivedTimeline(const InputEventTimeline& timeline) {
+void LatencyTrackerTest::assertReceivedTimeline(const InputEventTimeline& expectedTimeline) {
ASSERT_FALSE(mReceivedTimelines.empty());
- const InputEventTimeline& t = mReceivedTimelines.front();
- ASSERT_EQ(timeline, t);
+ const InputEventTimeline& received = mReceivedTimelines.front();
+ ASSERT_TRUE(timelinesAreEqual(received, expectedTimeline));
mReceivedTimelines.pop_front();
}
@@ -148,6 +187,11 @@
break;
}
}
+ if (!found) {
+ for (const InputEventTimeline& receivedTimeline : mReceivedTimelines) {
+ LOG(ERROR) << "Received timeline with eventTime=" << receivedTimeline.eventTime;
+ }
+ }
ASSERT_TRUE(found) << "Could not find expected timeline with eventTime="
<< expectedTimeline.eventTime;
}
@@ -170,14 +214,20 @@
* any additional ConnectionTimeline's.
*/
TEST_F(LatencyTrackerTest, TrackListener_DoesNotTriggerReporting) {
- mTracker->trackListener(/*inputEventId=*/1, /*eventTime=*/2,
- /*readTime=*/3, DEVICE_ID, {InputDeviceUsageSource::UNKNOWN},
- AMOTION_EVENT_ACTION_CANCEL, InputEventType::MOTION);
+ mTracker->trackListener(MotionArgsBuilder(AMOTION_EVENT_ACTION_CANCEL,
+ AINPUT_SOURCE_TOUCHSCREEN, /*inputEventId=*/1)
+ .eventTime(2)
+ .readTime(3)
+ .deviceId(DEVICE_ID)
+ .pointer(FIRST_TOUCH_POINTER)
+ .build());
triggerEventReporting(/*eventTime=*/2);
assertReceivedTimeline(
InputEventTimeline{/*eventTime=*/2,
- /*readTime=*/3, /*vendorId=*/0, /*productID=*/0,
- /*sources=*/{InputDeviceUsageSource::UNKNOWN},
+ /*readTime=*/3,
+ /*vendorId=*/0,
+ /*productID=*/0,
+ {InputDeviceUsageSource::TOUCHSCREEN},
/*inputEventActionType=*/InputEventActionType::UNKNOWN_INPUT_EVENT});
}
@@ -209,9 +259,13 @@
const auto& [connectionToken, expectedCT] = *expected.connectionTimelines.begin();
- mTracker->trackListener(inputEventId, expected.eventTime, expected.readTime, DEVICE_ID,
- {InputDeviceUsageSource::UNKNOWN}, AMOTION_EVENT_ACTION_CANCEL,
- InputEventType::MOTION);
+ mTracker->trackListener(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_CANCEL, AINPUT_SOURCE_TOUCHSCREEN, inputEventId)
+ .eventTime(expected.eventTime)
+ .readTime(expected.readTime)
+ .deviceId(DEVICE_ID)
+ .pointer(FIRST_TOUCH_POINTER)
+ .build());
mTracker->trackFinishedEvent(inputEventId, connectionToken, expectedCT.deliveryTime,
expectedCT.consumeTime, expectedCT.finishTime);
mTracker->trackGraphicsLatency(inputEventId, connectionToken, expectedCT.graphicsTimeline);
@@ -230,12 +284,20 @@
// In the following 2 calls to trackListener, the inputEventId's are the same, but event times
// are different.
- mTracker->trackListener(inputEventId, /*eventTime=*/1, readTime, DEVICE_ID,
- {InputDeviceUsageSource::UNKNOWN}, AMOTION_EVENT_ACTION_CANCEL,
- InputEventType::MOTION);
- mTracker->trackListener(inputEventId, /*eventTime=*/2, readTime, DEVICE_ID,
- {InputDeviceUsageSource::UNKNOWN}, AMOTION_EVENT_ACTION_CANCEL,
- InputEventType::MOTION);
+ mTracker->trackListener(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_CANCEL, AINPUT_SOURCE_TOUCHSCREEN, inputEventId)
+ .eventTime(1)
+ .readTime(readTime)
+ .deviceId(DEVICE_ID)
+ .pointer(FIRST_TOUCH_POINTER)
+ .build());
+ mTracker->trackListener(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_CANCEL, AINPUT_SOURCE_TOUCHSCREEN, inputEventId)
+ .eventTime(2)
+ .readTime(readTime)
+ .deviceId(DEVICE_ID)
+ .pointer(FIRST_TOUCH_POINTER)
+ .build());
triggerEventReporting(/*eventTime=*/2);
// Since we sent duplicate input events, the tracker should just delete all of them, because it
@@ -249,8 +311,7 @@
/*eventTime*/ 2,
/*readTime*/ 3,
/*vendorId=*/0,
- /*productId=*/0,
- /*sources=*/{InputDeviceUsageSource::UNKNOWN},
+ /*productId=*/0, {InputDeviceUsageSource::TOUCHSCREEN},
/*inputEventType=*/InputEventActionType::UNKNOWN_INPUT_EVENT);
timeline1.connectionTimelines.emplace(connection1,
ConnectionTimeline(/*deliveryTime*/ 6, /*consumeTime*/ 7,
@@ -266,8 +327,7 @@
/*eventTime=*/20,
/*readTime=*/30,
/*vendorId=*/0,
- /*productId=*/0,
- /*sources=*/{InputDeviceUsageSource::UNKNOWN},
+ /*productId=*/0, {InputDeviceUsageSource::TOUCHSCREEN},
/*inputEventActionType=*/InputEventActionType::UNKNOWN_INPUT_EVENT);
timeline2.connectionTimelines.emplace(connection2,
ConnectionTimeline(/*deliveryTime=*/60,
@@ -280,13 +340,21 @@
connectionTimeline2.setGraphicsTimeline(std::move(graphicsTimeline2));
// Start processing first event
- mTracker->trackListener(inputEventId1, timeline1.eventTime, timeline1.readTime, DEVICE_ID,
- {InputDeviceUsageSource::UNKNOWN}, AMOTION_EVENT_ACTION_CANCEL,
- InputEventType::MOTION);
+ mTracker->trackListener(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_CANCEL, AINPUT_SOURCE_TOUCHSCREEN, inputEventId1)
+ .eventTime(timeline1.eventTime)
+ .readTime(timeline1.readTime)
+ .deviceId(DEVICE_ID)
+ .pointer(FIRST_TOUCH_POINTER)
+ .build());
// Start processing second event
- mTracker->trackListener(inputEventId2, timeline2.eventTime, timeline2.readTime, DEVICE_ID,
- {InputDeviceUsageSource::UNKNOWN}, AMOTION_EVENT_ACTION_CANCEL,
- InputEventType::MOTION);
+ mTracker->trackListener(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_CANCEL, AINPUT_SOURCE_TOUCHSCREEN, inputEventId2)
+ .eventTime(timeline2.eventTime)
+ .readTime(timeline2.readTime)
+ .deviceId(DEVICE_ID)
+ .pointer(FIRST_TOUCH_POINTER)
+ .build());
mTracker->trackFinishedEvent(inputEventId1, connection1, connectionTimeline1.deliveryTime,
connectionTimeline1.consumeTime, connectionTimeline1.finishTime);
@@ -311,10 +379,13 @@
const sp<IBinder>& token = timeline.connectionTimelines.begin()->first;
for (size_t i = 1; i <= 100; i++) {
- mTracker->trackListener(/*inputEventId=*/i, timeline.eventTime, timeline.readTime,
- /*deviceId=*/DEVICE_ID,
- /*sources=*/{InputDeviceUsageSource::UNKNOWN},
- AMOTION_EVENT_ACTION_CANCEL, InputEventType::MOTION);
+ mTracker->trackListener(MotionArgsBuilder(AMOTION_EVENT_ACTION_CANCEL,
+ AINPUT_SOURCE_TOUCHSCREEN, /*inputEventId=*/i)
+ .eventTime(timeline.eventTime)
+ .readTime(timeline.readTime)
+ .deviceId(DEVICE_ID)
+ .pointer(FIRST_TOUCH_POINTER)
+ .build());
expectedTimelines.push_back(InputEventTimeline{timeline.eventTime, timeline.readTime,
timeline.vendorId, timeline.productId,
timeline.sources,
@@ -344,9 +415,13 @@
expectedCT.consumeTime, expectedCT.finishTime);
mTracker->trackGraphicsLatency(inputEventId, connection1, expectedCT.graphicsTimeline);
- mTracker->trackListener(inputEventId, expected.eventTime, expected.readTime, DEVICE_ID,
- {InputDeviceUsageSource::UNKNOWN}, AMOTION_EVENT_ACTION_CANCEL,
- InputEventType::MOTION);
+ mTracker->trackListener(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_CANCEL, AINPUT_SOURCE_TOUCHSCREEN, inputEventId)
+ .eventTime(expected.eventTime)
+ .readTime(expected.readTime)
+ .deviceId(DEVICE_ID)
+ .pointer(FIRST_TOUCH_POINTER)
+ .build());
triggerEventReporting(expected.eventTime);
assertReceivedTimeline(InputEventTimeline{expected.eventTime, expected.readTime,
expected.vendorId, expected.productId,
@@ -362,20 +437,25 @@
constexpr int32_t inputEventId = 1;
InputEventTimeline timeline(
/*eventTime*/ 2, /*readTime*/ 3,
- /*vendorId=*/50, /*productId=*/60,
- /*sources=*/
- {InputDeviceUsageSource::TOUCHSCREEN, InputDeviceUsageSource::STYLUS_DIRECT},
+ /*vendorId=*/50, /*productId=*/60, {InputDeviceUsageSource::STYLUS_DIRECT},
/*inputEventActionType=*/InputEventActionType::UNKNOWN_INPUT_EVENT);
InputDeviceInfo deviceInfo1 = generateTestDeviceInfo(
/*vendorId=*/5, /*productId=*/6, /*deviceId=*/DEVICE_ID + 1);
InputDeviceInfo deviceInfo2 = generateTestDeviceInfo(
/*vendorId=*/50, /*productId=*/60, /*deviceId=*/DEVICE_ID);
+ deviceInfo2.addSource(AINPUT_SOURCE_TOUCHSCREEN);
+ deviceInfo2.addSource(AINPUT_SOURCE_STYLUS);
mTracker->setInputDevices({deviceInfo1, deviceInfo2});
- mTracker->trackListener(inputEventId, timeline.eventTime, timeline.readTime, DEVICE_ID,
- {InputDeviceUsageSource::TOUCHSCREEN,
- InputDeviceUsageSource::STYLUS_DIRECT},
- AMOTION_EVENT_ACTION_CANCEL, InputEventType::MOTION);
+ mTracker->trackListener(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_CANCEL,
+ AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS, inputEventId)
+
+ .eventTime(timeline.eventTime)
+ .readTime(timeline.readTime)
+ .deviceId(DEVICE_ID)
+ .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(100).y(200))
+ .build());
triggerEventReporting(timeline.eventTime);
assertReceivedTimeline(timeline);
}
@@ -388,58 +468,74 @@
// Create timelines for different event types (Motion, Key)
InputEventTimeline motionDownTimeline(
/*eventTime*/ 2, /*readTime*/ 3,
- /*vendorId*/ 0, /*productId*/ 0,
- /*sources*/ {InputDeviceUsageSource::UNKNOWN},
- /*inputEventActionType*/ InputEventActionType::MOTION_ACTION_DOWN);
+ /*vendorId*/ 0, /*productId*/ 0, {InputDeviceUsageSource::TOUCHSCREEN},
+ InputEventActionType::MOTION_ACTION_DOWN);
InputEventTimeline motionMoveTimeline(
/*eventTime*/ 4, /*readTime*/ 5,
- /*vendorId*/ 0, /*productId*/ 0,
- /*sources*/ {InputDeviceUsageSource::UNKNOWN},
- /*inputEventActionType*/ InputEventActionType::MOTION_ACTION_MOVE);
+ /*vendorId*/ 0, /*productId*/ 0, {InputDeviceUsageSource::TOUCHSCREEN},
+ InputEventActionType::MOTION_ACTION_MOVE);
InputEventTimeline motionUpTimeline(
/*eventTime*/ 6, /*readTime*/ 7,
- /*vendorId*/ 0, /*productId*/ 0,
- /*sources*/ {InputDeviceUsageSource::UNKNOWN},
- /*inputEventActionType*/ InputEventActionType::MOTION_ACTION_UP);
+ /*vendorId*/ 0, /*productId*/ 0, {InputDeviceUsageSource::TOUCHSCREEN},
+ InputEventActionType::MOTION_ACTION_UP);
InputEventTimeline keyDownTimeline(
/*eventTime*/ 8, /*readTime*/ 9,
- /*vendorId*/ 0, /*productId*/ 0,
- /*sources*/ {InputDeviceUsageSource::UNKNOWN},
- /*inputEventActionType*/ InputEventActionType::KEY);
+ /*vendorId*/ 0, /*productId*/ 0, {InputDeviceUsageSource::BUTTONS},
+ InputEventActionType::KEY);
InputEventTimeline keyUpTimeline(
/*eventTime*/ 10, /*readTime*/ 11,
- /*vendorId*/ 0, /*productId*/ 0,
- /*sources*/ {InputDeviceUsageSource::UNKNOWN},
- /*inputEventActionType*/ InputEventActionType::KEY);
+ /*vendorId*/ 0, /*productId*/ 0, {InputDeviceUsageSource::BUTTONS},
+ InputEventActionType::KEY);
InputEventTimeline unknownTimeline(
/*eventTime*/ 12, /*readTime*/ 13,
- /*vendorId*/ 0, /*productId*/ 0,
- /*sources*/ {InputDeviceUsageSource::UNKNOWN},
- /*inputEventActionType*/ InputEventActionType::UNKNOWN_INPUT_EVENT);
+ /*vendorId*/ 0, /*productId*/ 0, {InputDeviceUsageSource::TOUCHSCREEN},
+ InputEventActionType::UNKNOWN_INPUT_EVENT);
- mTracker->trackListener(inputEventId, motionDownTimeline.eventTime, motionDownTimeline.readTime,
- DEVICE_ID, motionDownTimeline.sources, AMOTION_EVENT_ACTION_DOWN,
- InputEventType::MOTION);
- mTracker->trackListener(inputEventId + 1, motionMoveTimeline.eventTime,
- motionMoveTimeline.readTime, DEVICE_ID, motionMoveTimeline.sources,
- AMOTION_EVENT_ACTION_MOVE, InputEventType::MOTION);
- mTracker->trackListener(inputEventId + 2, motionUpTimeline.eventTime, motionUpTimeline.readTime,
- DEVICE_ID, motionUpTimeline.sources, AMOTION_EVENT_ACTION_UP,
- InputEventType::MOTION);
- mTracker->trackListener(inputEventId + 3, keyDownTimeline.eventTime, keyDownTimeline.readTime,
- DEVICE_ID, keyDownTimeline.sources, AKEY_EVENT_ACTION_DOWN,
- InputEventType::KEY);
- mTracker->trackListener(inputEventId + 4, keyUpTimeline.eventTime, keyUpTimeline.readTime,
- DEVICE_ID, keyUpTimeline.sources, AKEY_EVENT_ACTION_UP,
- InputEventType::KEY);
- mTracker->trackListener(inputEventId + 5, unknownTimeline.eventTime, unknownTimeline.readTime,
- DEVICE_ID, unknownTimeline.sources, AMOTION_EVENT_ACTION_POINTER_DOWN,
- InputEventType::MOTION);
+ mTracker->trackListener(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, inputEventId)
+ .eventTime(motionDownTimeline.eventTime)
+ .readTime(motionDownTimeline.readTime)
+ .deviceId(DEVICE_ID)
+ .pointer(FIRST_TOUCH_POINTER)
+ .build());
+ mTracker->trackListener(MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
+ inputEventId + 1)
+ .eventTime(motionMoveTimeline.eventTime)
+ .readTime(motionMoveTimeline.readTime)
+ .deviceId(DEVICE_ID)
+ .pointer(FIRST_TOUCH_POINTER)
+ .build());
+ mTracker->trackListener(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, inputEventId + 2)
+ .eventTime(motionUpTimeline.eventTime)
+ .readTime(motionUpTimeline.readTime)
+ .deviceId(DEVICE_ID)
+ .pointer(FIRST_TOUCH_POINTER)
+ .build());
+ mTracker->trackListener(
+ KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD, inputEventId + 3)
+ .eventTime(keyDownTimeline.eventTime)
+ .readTime(keyDownTimeline.readTime)
+ .deviceId(DEVICE_ID)
+ .build());
+ mTracker->trackListener(
+ KeyArgsBuilder(AKEY_EVENT_ACTION_UP, AINPUT_SOURCE_KEYBOARD, inputEventId + 4)
+ .eventTime(keyUpTimeline.eventTime)
+ .readTime(keyUpTimeline.readTime)
+ .deviceId(DEVICE_ID)
+ .build());
+ mTracker->trackListener(MotionArgsBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN,
+ AINPUT_SOURCE_TOUCHSCREEN, inputEventId + 5)
+ .eventTime(unknownTimeline.eventTime)
+ .readTime(unknownTimeline.readTime)
+ .deviceId(DEVICE_ID)
+ .pointer(FIRST_TOUCH_POINTER)
+ .build());
triggerEventReporting(unknownTimeline.eventTime);
diff --git a/services/inputflinger/tests/TestEventMatchers.h b/services/inputflinger/tests/TestEventMatchers.h
index 6fa3365..f58d8fd 100644
--- a/services/inputflinger/tests/TestEventMatchers.h
+++ b/services/inputflinger/tests/TestEventMatchers.h
@@ -540,6 +540,34 @@
return WithKeyCodeMatcher(keyCode);
}
+/// Scan code
+class WithScanCodeMatcher {
+public:
+ using is_gtest_matcher = void;
+ explicit WithScanCodeMatcher(int32_t scanCode) : mScanCode(scanCode) {}
+
+ bool MatchAndExplain(const NotifyKeyArgs& args, std::ostream*) const {
+ return mScanCode == args.scanCode;
+ }
+
+ bool MatchAndExplain(const KeyEvent& event, std::ostream*) const {
+ return mScanCode == event.getKeyCode();
+ }
+
+ void DescribeTo(std::ostream* os) const {
+ *os << "with scan code " << KeyEvent::getLabel(mScanCode);
+ }
+
+ void DescribeNegationTo(std::ostream* os) const { *os << "wrong scan code"; }
+
+private:
+ const int32_t mScanCode;
+};
+
+inline WithScanCodeMatcher WithScanCode(int32_t scanCode) {
+ return WithScanCodeMatcher(scanCode);
+}
+
/// EventId
class WithEventIdMatcher {
public:
diff --git a/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp
index 5442a65..64f3c27 100644
--- a/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp
@@ -171,6 +171,10 @@
void notifyMouseCursorFadedOnTyping() override { reader->notifyMouseCursorFadedOnTyping(); }
+ bool setKernelWakeEnabled(int32_t deviceId, bool enabled) override {
+ return reader->setKernelWakeEnabled(deviceId, enabled);
+ }
+
private:
std::unique_ptr<InputReaderInterface> reader;
};
diff --git a/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp b/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp
index 908fa40..157a333 100644
--- a/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp
@@ -19,6 +19,7 @@
#include "../../InputDeviceMetricsSource.h"
#include "../InputEventTimeline.h"
+#include "NotifyArgsBuilders.h"
#include "dispatcher/LatencyTracker.h"
namespace android {
@@ -61,40 +62,49 @@
// Make some pre-defined tokens to ensure that some timelines are complete.
std::array<sp<IBinder> /*token*/, 10> predefinedTokens;
- for (size_t i = 0; i < predefinedTokens.size(); i++) {
- predefinedTokens[i] = sp<BBinder>::make();
+ for (sp<IBinder>& token : predefinedTokens) {
+ token = sp<BBinder>::make();
}
// Randomly invoke LatencyTracker api's until randomness is exhausted.
while (fdp.remaining_bytes() > 0) {
fdp.PickValueInArray<std::function<void()>>({
[&]() -> void {
- int32_t inputEventId = fdp.ConsumeIntegral<int32_t>();
- nsecs_t eventTime = fdp.ConsumeIntegral<nsecs_t>();
- nsecs_t readTime = fdp.ConsumeIntegral<nsecs_t>();
+ const int32_t inputEventId = fdp.ConsumeIntegral<int32_t>();
+ const nsecs_t eventTime = fdp.ConsumeIntegral<nsecs_t>();
+ const nsecs_t readTime = fdp.ConsumeIntegral<nsecs_t>();
const DeviceId deviceId = fdp.ConsumeIntegral<int32_t>();
+ const int32_t source = fdp.ConsumeIntegral<int32_t>();
std::set<InputDeviceUsageSource> sources = {
fdp.ConsumeEnum<InputDeviceUsageSource>()};
const int32_t inputEventActionType = fdp.ConsumeIntegral<int32_t>();
const InputEventType inputEventType = fdp.ConsumeEnum<InputEventType>();
- tracker.trackListener(inputEventId, eventTime, readTime, deviceId, sources,
- inputEventActionType, inputEventType);
+ const NotifyMotionArgs args =
+ MotionArgsBuilder(inputEventActionType, source, inputEventId)
+ .eventTime(eventTime)
+ .readTime(readTime)
+ .deviceId(deviceId)
+ .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER)
+ .x(100)
+ .y(200))
+ .build();
+ tracker.trackListener(args);
},
[&]() -> void {
- int32_t inputEventId = fdp.ConsumeIntegral<int32_t>();
+ const int32_t inputEventId = fdp.ConsumeIntegral<int32_t>();
sp<IBinder> connectionToken = getConnectionToken(fdp, predefinedTokens);
- nsecs_t deliveryTime = fdp.ConsumeIntegral<nsecs_t>();
- nsecs_t consumeTime = fdp.ConsumeIntegral<nsecs_t>();
- nsecs_t finishTime = fdp.ConsumeIntegral<nsecs_t>();
+ const nsecs_t deliveryTime = fdp.ConsumeIntegral<nsecs_t>();
+ const nsecs_t consumeTime = fdp.ConsumeIntegral<nsecs_t>();
+ const nsecs_t finishTime = fdp.ConsumeIntegral<nsecs_t>();
tracker.trackFinishedEvent(inputEventId, connectionToken, deliveryTime,
consumeTime, finishTime);
},
[&]() -> void {
- int32_t inputEventId = fdp.ConsumeIntegral<int32_t>();
+ const int32_t inputEventId = fdp.ConsumeIntegral<int32_t>();
sp<IBinder> connectionToken = getConnectionToken(fdp, predefinedTokens);
- std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline;
- for (size_t i = 0; i < graphicsTimeline.size(); i++) {
- graphicsTimeline[i] = fdp.ConsumeIntegral<nsecs_t>();
+ std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline{};
+ for (nsecs_t& t : graphicsTimeline) {
+ t = fdp.ConsumeIntegral<nsecs_t>();
}
tracker.trackGraphicsLatency(inputEventId, connectionToken, graphicsTimeline);
},
diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h
index fa8270a..60c676d 100644
--- a/services/inputflinger/tests/fuzzers/MapperHelpers.h
+++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h
@@ -269,6 +269,9 @@
status_t enableDevice(int32_t deviceId) override { return mFdp->ConsumeIntegral<status_t>(); }
status_t disableDevice(int32_t deviceId) override { return mFdp->ConsumeIntegral<status_t>(); }
void sysfsNodeChanged(const std::string& sysfsNodePath) override {}
+ bool setKernelWakeEnabled(int32_t deviceId, bool enabled) override {
+ return mFdp->ConsumeBool();
+ }
};
class FuzzInputReaderPolicy : public InputReaderPolicyInterface {
diff --git a/services/stats/Android.bp b/services/stats/Android.bp
index 6b99627..f698515 100644
--- a/services/stats/Android.bp
+++ b/services/stats/Android.bp
@@ -7,6 +7,11 @@
default_applicable_licenses: ["frameworks_native_license"],
}
+vintf_fragment {
+ name: "android.frameworks.stats-service.xml",
+ src: "android.frameworks.stats-service.xml",
+}
+
cc_library_shared {
name: "libstatshidl",
srcs: [
@@ -38,7 +43,7 @@
local_include_dirs: [
"include/stats",
],
- vintf_fragments: [
+ vintf_fragment_modules: [
"android.frameworks.stats-service.xml",
],
}
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 7babd17..e176569 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -82,6 +82,7 @@
"libpowermanager",
"libprocessgroup",
"libprotobuf-cpp-lite",
+ "libstatslog_surfaceflinger",
"libsync",
"libui",
"libutils",
@@ -147,6 +148,46 @@
},
}
+// libsurfaceflinger_backend_{headers|sources} are a step towards pulling out
+// the "backend" sources to clean up the dependency graph between
+// CompositionEngine and SurfaceFlinger. Completing the cleanup would require
+// moving the headers in particular so that the dependency can strictly be a
+// DAG. There would certainly be additional cleanups: VirtualDisplaySurface.cpp
+// and FrameBufferSurface.cpp likely belong in CompositionEngine for example.
+cc_library_headers {
+ name: "libsurfaceflinger_backend_headers",
+ export_include_dirs: ["."],
+ static_libs: ["libserviceutils"],
+ export_static_lib_headers: ["libserviceutils"],
+
+ shared_libs: [
+ "android.hardware.configstore-utils",
+ "android.hardware.configstore@1.0",
+ "android.hardware.configstore@1.1",
+ "libbinder_ndk",
+ ],
+ export_shared_lib_headers: [
+ "android.hardware.configstore-utils",
+ "android.hardware.configstore@1.0",
+ "android.hardware.configstore@1.1",
+ "libbinder_ndk",
+ ],
+}
+
+filegroup {
+ name: "libsurfaceflinger_backend_sources",
+ srcs: [
+ "DisplayHardware/AidlComposerHal.cpp",
+ "DisplayHardware/ComposerHal.cpp",
+ "DisplayHardware/FramebufferSurface.cpp",
+ "DisplayHardware/HWC2.cpp",
+ "DisplayHardware/HWComposer.cpp",
+ "DisplayHardware/HidlComposerHal.cpp",
+ "DisplayHardware/PowerAdvisor.cpp",
+ "DisplayHardware/VirtualDisplaySurface.cpp",
+ ],
+}
+
cc_library_headers {
name: "libsurfaceflinger_headers",
export_include_dirs: ["."],
@@ -157,20 +198,13 @@
filegroup {
name: "libsurfaceflinger_sources",
srcs: [
+ ":libsurfaceflinger_backend_sources",
"BackgroundExecutor.cpp",
"Client.cpp",
"ClientCache.cpp",
"Display/DisplayModeController.cpp",
"Display/DisplaySnapshot.cpp",
"DisplayDevice.cpp",
- "DisplayHardware/AidlComposerHal.cpp",
- "DisplayHardware/ComposerHal.cpp",
- "DisplayHardware/FramebufferSurface.cpp",
- "DisplayHardware/HWC2.cpp",
- "DisplayHardware/HWComposer.cpp",
- "DisplayHardware/HidlComposerHal.cpp",
- "DisplayHardware/PowerAdvisor.cpp",
- "DisplayHardware/VirtualDisplaySurface.cpp",
"DisplayRenderArea.cpp",
"Effects/Daltonizer.cpp",
"FrontEnd/LayerCreationArgs.cpp",
@@ -313,3 +347,37 @@
"libSurfaceFlingerProperties",
],
}
+
+cc_library {
+ name: "libstatslog_surfaceflinger",
+ generated_sources: ["statslog_surfaceflinger.cpp"],
+ generated_headers: ["statslog_surfaceflinger.h"],
+ export_generated_headers: ["statslog_surfaceflinger.h"],
+ shared_libs: [
+ "libbinder",
+ "libstatsbootstrap",
+ "libutils",
+ "android.os.statsbootstrap_aidl-cpp",
+ ],
+}
+
+genrule {
+ name: "statslog_surfaceflinger.h",
+ tools: ["stats-log-api-gen"],
+ cmd: "$(location stats-log-api-gen) --header $(genDir)/statslog_surfaceflinger.h" +
+ " --module surfaceflinger --namespace android,surfaceflinger,stats --bootstrap",
+ out: [
+ "statslog_surfaceflinger.h",
+ ],
+}
+
+genrule {
+ name: "statslog_surfaceflinger.cpp",
+ tools: ["stats-log-api-gen"],
+ cmd: "$(location stats-log-api-gen) --cpp $(genDir)/statslog_surfaceflinger.cpp" +
+ " --module surfaceflinger --namespace android,surfaceflinger,stats" +
+ " --importHeader statslog_surfaceflinger.h --bootstrap",
+ out: [
+ "statslog_surfaceflinger.cpp",
+ ],
+}
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index b4ac9ba..7095b9d 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -59,7 +59,7 @@
"android.hardware.graphics.composer@2.3-command-buffer",
"android.hardware.graphics.composer@2.4-command-buffer",
"android.hardware.graphics.composer3-command-buffer",
- "libsurfaceflinger_headers",
+ "libsurfaceflinger_backend_headers",
],
}
@@ -141,6 +141,8 @@
],
srcs: [
":libcompositionengine_sources",
+ ":libsurfaceflinger_backend_mock_sources",
+ ":libsurfaceflinger_backend_sources",
"tests/planner/CachedSetTest.cpp",
"tests/planner/FlattenerTest.cpp",
"tests/planner/LayerStateTest.cpp",
@@ -151,14 +153,14 @@
"tests/DisplayTest.cpp",
"tests/HwcAsyncWorkerTest.cpp",
"tests/HwcBufferCacheTest.cpp",
- "tests/MockHWC2.cpp",
- "tests/MockHWComposer.cpp",
- "tests/MockPowerAdvisor.cpp",
"tests/OutputLayerTest.cpp",
"tests/OutputTest.cpp",
"tests/ProjectionSpaceTest.cpp",
"tests/RenderSurfaceTest.cpp",
],
+ header_libs: [
+ "libsurfaceflinger_backend_mock_headers",
+ ],
static_libs: [
"libcompositionengine_mocks",
"libgui_mocks",
@@ -167,6 +169,7 @@
"libgtest",
],
shared_libs: [
+ "libbinder_ndk",
// For some reason, libvulkan isn't picked up from librenderengine
// Probably ASAN related?
"libvulkan",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index 14a8fd6..8a91a07 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -19,6 +19,7 @@
#include <cstdint>
#include <android/gui/CachingHint.h>
+#include <gui/DisplayLuts.h>
#include <gui/HdrMetadata.h>
#include <math/mat4.h>
#include <ui/BlurRegion.h>
@@ -219,6 +220,9 @@
float desiredHdrSdrRatio = 1.f;
gui::CachingHint cachingHint = gui::CachingHint::Enabled;
+
+ std::shared_ptr<gui::DisplayLuts> luts;
+
virtual ~LayerFECompositionState();
// Debugging
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 191d475..556aa24 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -329,6 +329,8 @@
virtual bool isPowerHintSessionGpuReportingEnabled() = 0;
virtual void cacheClientCompositionRequests(uint32_t cacheSize) = 0;
virtual bool canPredictCompositionStrategy(const CompositionRefreshArgs&) = 0;
+ virtual const aidl::android::hardware::graphics::composer3::OverlayProperties*
+ getOverlaySupport() = 0;
};
} // namespace compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
index dcfe21a..80c5124 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
@@ -93,7 +93,10 @@
// transform, if needed.
virtual void updateCompositionState(
bool includeGeometry, bool forceClientComposition,
- ui::Transform::RotationFlags internalDisplayRotationFlags) = 0;
+ ui::Transform::RotationFlags internalDisplayRotationFlags,
+ const std::optional<std::vector<
+ std::optional<aidl::android::hardware::graphics::composer3::LutProperties>>>
+ properties) = 0;
// Writes the geometry state to the HWC, or does nothing if this layer does
// not use the HWC. If includeGeometry is false, the geometry state can be
@@ -129,8 +132,10 @@
virtual void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) = 0;
// Applies a HWC device layer lut
- virtual void applyDeviceLayerLut(aidl::android::hardware::graphics::composer3::LutProperties,
- ndk::ScopedFileDescriptor) = 0;
+ virtual void applyDeviceLayerLut(
+ ndk::ScopedFileDescriptor,
+ std::vector<std::pair<
+ int, aidl::android::hardware::graphics::composer3::LutProperties>>) = 0;
// Returns true if the composition settings scale pixels
virtual bool needsFiltering() const = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index a39abb4..d8466ff 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -103,6 +103,8 @@
DisplayId mId;
bool mIsDisconnected = false;
Hwc2::PowerAdvisor* mPowerAdvisor = nullptr;
+ const aidl::android::hardware::graphics::composer3::OverlayProperties* getOverlaySupport()
+ override;
};
// This template factory function standardizes the implementation details of the
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 9990a74..69e1efc 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -164,6 +164,8 @@
bool mustRecompose() const;
const std::string& getNamePlusId() const { return mNamePlusId; }
+ const aidl::android::hardware::graphics::composer3::OverlayProperties* getOverlaySupport()
+ override;
private:
void dirtyEntireOutput();
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index 354a441..0c7e4dd 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -31,6 +31,8 @@
#include <aidl/android/hardware/graphics/composer3/Composition.h>
+using aidl::android::hardware::graphics::composer3::LutProperties;
+
namespace android::compositionengine {
struct LayerFECompositionState;
@@ -48,7 +50,9 @@
void uncacheBuffers(const std::vector<uint64_t>& bufferIdsToUncache) override;
void updateCompositionState(bool includeGeometry, bool forceClientComposition,
- ui::Transform::RotationFlags) override;
+ ui::Transform::RotationFlags,
+ const std::optional<std::vector<std::optional<LutProperties>>>
+ properties = std::nullopt) override;
void writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t z, bool zIsOverridden,
bool isPeekingThrough) override;
void writeCursorPositionToHWC() const override;
@@ -60,8 +64,8 @@
aidl::android::hardware::graphics::composer3::Composition) override;
void prepareForDeviceLayerRequests() override;
void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) override;
- void applyDeviceLayerLut(aidl::android::hardware::graphics::composer3::LutProperties,
- ndk::ScopedFileDescriptor) override;
+ void applyDeviceLayerLut(ndk::ScopedFileDescriptor,
+ std::vector<std::pair<int, LutProperties>>) override;
bool needsFiltering() const override;
std::optional<LayerFE::LayerSettings> getOverrideCompositionSettings() const override;
@@ -92,10 +96,13 @@
void writeCompositionTypeToHWC(HWC2::Layer*,
aidl::android::hardware::graphics::composer3::Composition,
bool isPeekingThrough, bool skipLayer);
+ void writeLutToHWC(HWC2::Layer*, const LayerFECompositionState&);
void detectDisallowedCompositionTypeChange(
aidl::android::hardware::graphics::composer3::Composition from,
aidl::android::hardware::graphics::composer3::Composition to) const;
bool isClientCompositionForced(bool isPeekingThrough) const;
+ void updateLuts(std::shared_ptr<gui::DisplayLuts> luts,
+ const std::optional<std::vector<std::optional<LutProperties>>>& properties);
};
// This template factory function standardizes the implementation details of the
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
index 6c419da..28216a4 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
@@ -18,6 +18,7 @@
#include <compositionengine/ProjectionSpace.h>
#include <compositionengine/impl/HwcBufferCache.h>
+#include <gui/DisplayLuts.h>
#include <renderengine/ExternalTexture.h>
#include <ui/FloatRect.h>
#include <ui/GraphicTypes.h>
@@ -151,6 +152,9 @@
// True when this layer was skipped as part of SF-side layer caching.
bool layerSkipped = false;
+
+ // lut information
+ std::shared_ptr<gui::DisplayLuts> luts;
};
// The HWC state is optional, and is only set up if there is any potential
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index d5bf2b5..33cdc54 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -140,6 +140,8 @@
MOCK_METHOD(void, setHintSessionRequiresRenderEngine, (bool requiresRenderEngine));
MOCK_METHOD(bool, isPowerHintSessionEnabled, ());
MOCK_METHOD(bool, isPowerHintSessionGpuReportingEnabled, ());
+ MOCK_METHOD((const aidl::android::hardware::graphics::composer3::OverlayProperties*),
+ getOverlaySupport, ());
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
index 48c2f9c..12f2094 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
@@ -43,7 +43,10 @@
MOCK_CONST_METHOD0(getState, const impl::OutputLayerCompositionState&());
MOCK_METHOD0(editState, impl::OutputLayerCompositionState&());
- MOCK_METHOD3(updateCompositionState, void(bool, bool, ui::Transform::RotationFlags));
+ MOCK_METHOD(void, updateCompositionState,
+ (bool, bool, ui::Transform::RotationFlags,
+ (const std::optional<std::vector<std::optional<
+ aidl::android::hardware::graphics::composer3::LutProperties>>>)));
MOCK_METHOD5(writeStateToHWC, void(bool, bool, uint32_t, bool, bool));
MOCK_CONST_METHOD0(writeCursorPositionToHWC, void());
@@ -57,8 +60,9 @@
MOCK_CONST_METHOD0(needsFiltering, bool());
MOCK_CONST_METHOD0(getOverrideCompositionSettings, std::optional<LayerFE::LayerSettings>());
MOCK_METHOD(void, applyDeviceLayerLut,
- (aidl::android::hardware::graphics::composer3::LutProperties,
- ndk::ScopedFileDescriptor));
+ (ndk::ScopedFileDescriptor,
+ (std::vector<std::pair<
+ int, aidl::android::hardware::graphics::composer3::LutProperties>>)));
MOCK_CONST_METHOD1(dump, void(std::string&));
};
diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
index 5c5d0cd..cfcce47 100644
--- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
@@ -198,25 +198,23 @@
// these buffers and fire a NO_FENCE to release it. This ensures that all
// promises for buffer releases are fulfilled at the end of composition.
void CompositionEngine::postComposition(CompositionRefreshArgs& args) {
- if (FlagManager::getInstance().ce_fence_promise()) {
- SFTRACE_CALL();
- ALOGV(__FUNCTION__);
+ SFTRACE_CALL();
+ ALOGV(__FUNCTION__);
- for (auto& layerFE : args.layers) {
- if (layerFE->getReleaseFencePromiseStatus() ==
- LayerFE::ReleaseFencePromiseStatus::INITIALIZED) {
- layerFE->setReleaseFence(Fence::NO_FENCE);
- }
+ for (auto& layerFE : args.layers) {
+ if (layerFE->getReleaseFencePromiseStatus() ==
+ LayerFE::ReleaseFencePromiseStatus::INITIALIZED) {
+ layerFE->setReleaseFence(Fence::NO_FENCE);
}
+ }
- // List of layersWithQueuedFrames does not necessarily overlap with
- // list of layers, so those layersWithQueuedFrames also need any
- // unfulfilled promises to be resolved for completeness.
- for (auto& layerFE : args.layersWithQueuedFrames) {
- if (layerFE->getReleaseFencePromiseStatus() ==
- LayerFE::ReleaseFencePromiseStatus::INITIALIZED) {
- layerFE->setReleaseFence(Fence::NO_FENCE);
- }
+ // List of layersWithQueuedFrames does not necessarily overlap with
+ // list of layers, so those layersWithQueuedFrames also need any
+ // unfulfilled promises to be resolved for completeness.
+ for (auto& layerFE : args.layersWithQueuedFrames) {
+ if (layerFE->getReleaseFencePromiseStatus() ==
+ LayerFE::ReleaseFencePromiseStatus::INITIALIZED) {
+ layerFE->setReleaseFence(Fence::NO_FENCE);
}
}
}
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index b0164b7..1825065 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -370,8 +370,8 @@
if (auto lutsIt = layerLuts.find(hwcLayer); lutsIt != layerLuts.end()) {
if (auto mapperIt = mapper.find(hwcLayer); mapperIt != mapper.end()) {
- layer->applyDeviceLayerLut(lutsIt->second,
- ndk::ScopedFileDescriptor(mapperIt->second.release()));
+ layer->applyDeviceLayerLut(ndk::ScopedFileDescriptor(mapperIt->second.release()),
+ lutsIt->second);
}
}
}
@@ -457,6 +457,11 @@
mPowerAdvisor->setRequiresRenderEngine(mId, requiresRenderEngine);
}
+const aidl::android::hardware::graphics::composer3::OverlayProperties*
+Display::getOverlaySupport() {
+ return &getCompositionEngine().getHwComposer().getOverlaySupport();
+}
+
void Display::finishFrame(GpuCompositionResult&& result) {
// We only need to actually compose the display if:
// 1) It is being handled by hardware composer, which may need this to
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 2d8f98f..bb45613 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -813,11 +813,14 @@
mLayerRequestingBackgroundBlur = findLayerRequestingBackgroundComposition();
bool forceClientComposition = mLayerRequestingBackgroundBlur != nullptr;
+ auto* properties = getOverlaySupport();
+
for (auto* layer : getOutputLayersOrderedByZ()) {
layer->updateCompositionState(refreshArgs.updatingGeometryThisFrame,
refreshArgs.devOptForceClientComposition ||
forceClientComposition,
- refreshArgs.internalDisplayRotationFlags);
+ refreshArgs.internalDisplayRotationFlags,
+ properties ? properties->lutProperties : std::nullopt);
if (mLayerRequestingBackgroundBlur == layer) {
forceClientComposition = false;
@@ -1610,13 +1613,7 @@
releaseFence =
Fence::merge("LayerRelease", releaseFence, frame.clientTargetAcquireFence);
}
- if (FlagManager::getInstance().ce_fence_promise()) {
- layer->getLayerFE().setReleaseFence(releaseFence);
- } else {
- layer->getLayerFE()
- .onLayerDisplayed(ftl::yield<FenceResult>(std::move(releaseFence)).share(),
- outputState.layerFilter.layerStack);
- }
+ layer->getLayerFE().setReleaseFence(releaseFence);
}
// We've got a list of layers needing fences, that are disjoint with
@@ -1624,12 +1621,7 @@
// supply them with the present fence.
for (auto& weakLayer : mReleasedLayers) {
if (const auto layer = weakLayer.promote()) {
- if (FlagManager::getInstance().ce_fence_promise()) {
- layer->setReleaseFence(frame.presentFence);
- } else {
- layer->onLayerDisplayed(ftl::yield<FenceResult>(frame.presentFence).share(),
- outputState.layerFilter.layerStack);
- }
+ layer->setReleaseFence(frame.presentFence);
}
}
@@ -1689,6 +1681,10 @@
editState().treat170mAsSrgb = enable;
}
+const aidl::android::hardware::graphics::composer3::OverlayProperties* Output::getOverlaySupport() {
+ return nullptr;
+}
+
bool Output::canPredictCompositionStrategy(const CompositionRefreshArgs& refreshArgs) {
uint64_t lastOutputLayerHash = getState().lastOutputLayerHash;
uint64_t outputLayerHash = getState().outputLayerHash;
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 2d46dc0..934909d 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -38,7 +38,7 @@
#pragma clang diagnostic pop // ignored "-Wconversion"
using aidl::android::hardware::graphics::composer3::Composition;
-using aidl::android::hardware::graphics::composer3::LutProperties;
+using aidl::android::hardware::graphics::composer3::Luts;
namespace android::compositionengine {
@@ -285,9 +285,50 @@
return transform.getOrientation();
}
+void OutputLayer::updateLuts(
+ std::shared_ptr<gui::DisplayLuts> layerFEStateLut,
+ const std::optional<std::vector<std::optional<LutProperties>>>& properties) {
+ auto& state = editState();
+
+ if (!properties) {
+ // GPU composition if no Hwc Luts
+ state.forceClientComposition = true;
+ return;
+ }
+
+ std::vector<LutProperties> hwcLutProperties;
+ for (auto& p : *properties) {
+ if (p) {
+ hwcLutProperties.emplace_back(*p);
+ }
+ }
+
+ for (const auto& inputLut : layerFEStateLut->lutProperties) {
+ bool foundInHwcLuts = false;
+ for (const auto& hwcLut : hwcLutProperties) {
+ if (static_cast<int32_t>(hwcLut.dimension) ==
+ static_cast<int32_t>(inputLut.dimension) &&
+ hwcLut.size == inputLut.size &&
+ std::find(hwcLut.samplingKeys.begin(), hwcLut.samplingKeys.end(),
+ static_cast<LutProperties::SamplingKey>(inputLut.samplingKey)) !=
+ hwcLut.samplingKeys.end()) {
+ foundInHwcLuts = true;
+ break;
+ }
+ }
+ // if any lut properties of layerFEStateLut can not be found in hwcLutProperties,
+ // GPU composition instead
+ if (!foundInHwcLuts) {
+ state.forceClientComposition = true;
+ return;
+ }
+ }
+}
+
void OutputLayer::updateCompositionState(
bool includeGeometry, bool forceClientComposition,
- ui::Transform::RotationFlags internalDisplayRotationFlags) {
+ ui::Transform::RotationFlags internalDisplayRotationFlags,
+ const std::optional<std::vector<std::optional<LutProperties>>> properties) {
const auto* layerFEState = getLayerFE().getCompositionState();
if (!layerFEState) {
return;
@@ -368,6 +409,11 @@
state.whitePointNits = layerBrightnessNits;
}
+ const auto& layerFEStateLut = layerFEState->luts;
+ if (layerFEStateLut) {
+ updateLuts(layerFEStateLut, properties);
+ }
+
// These are evaluated every frame as they can potentially change at any
// time.
if (layerFEState->forceClientComposition || !profile.isDataspaceSupported(state.dataspace) ||
@@ -420,6 +466,8 @@
writeCompositionTypeToHWC(hwcLayer.get(), requestedCompositionType, isPeekingThrough,
skipLayer);
+ writeLutToHWC(hwcLayer.get(), *outputIndependentState);
+
if (requestedCompositionType == Composition::SOLID_COLOR) {
writeSolidColorStateToHWC(hwcLayer.get(), *outputIndependentState);
}
@@ -513,6 +561,40 @@
}
}
+void OutputLayer::writeLutToHWC(HWC2::Layer* hwcLayer,
+ const LayerFECompositionState& outputIndependentState) {
+ if (!outputIndependentState.luts) {
+ return;
+ }
+ auto& lutFileDescriptor = outputIndependentState.luts->getLutFileDescriptor();
+ auto lutOffsets = outputIndependentState.luts->offsets;
+ auto& lutProperties = outputIndependentState.luts->lutProperties;
+
+ std::vector<LutProperties> aidlProperties;
+ aidlProperties.reserve(lutProperties.size());
+ for (size_t i = 0; i < lutOffsets.size(); i++) {
+ LutProperties properties;
+ properties.dimension = static_cast<LutProperties::Dimension>(lutProperties[i].dimension);
+ properties.size = lutProperties[i].size;
+ properties.samplingKeys = {
+ static_cast<LutProperties::SamplingKey>(lutProperties[i].samplingKey)};
+ aidlProperties.emplace_back(properties);
+ }
+
+ Luts luts;
+ luts.pfd = ndk::ScopedFileDescriptor(dup(lutFileDescriptor.get()));
+ luts.offsets = lutOffsets;
+ luts.lutProperties = std::move(aidlProperties);
+
+ switch (auto error = hwcLayer->setLuts(luts)) {
+ case hal::Error::NONE:
+ break;
+ default:
+ ALOGE("[%s] Failed to set Luts: %s (%d)", getLayerFE().getDebugName(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+}
+
void OutputLayer::writeOutputDependentPerFrameStateToHWC(HWC2::Layer* hwcLayer) {
const auto& outputDependentState = getState();
@@ -849,10 +931,29 @@
}
}
-void OutputLayer::applyDeviceLayerLut(LutProperties /*lutProperties*/,
- ndk::ScopedFileDescriptor /*lutPfd*/) {
- // TODO(b/329472856): decode the shared memory of the pfd, and store the lut data into
- // OutputLayerCompositionState#hwc struct
+void OutputLayer::applyDeviceLayerLut(
+ ndk::ScopedFileDescriptor lutFileDescriptor,
+ std::vector<std::pair<int, LutProperties>> lutOffsetsAndProperties) {
+ auto& state = editState();
+ LOG_FATAL_IF(!state.hwc);
+ auto& hwcState = *state.hwc;
+ std::vector<int32_t> offsets;
+ std::vector<int32_t> dimensions;
+ std::vector<int32_t> sizes;
+ std::vector<int32_t> samplingKeys;
+ for (const auto& [offset, properties] : lutOffsetsAndProperties) {
+ // The Lut(s) that comes back through CommandResultPayload should be
+ // only one sampling key.
+ if (properties.samplingKeys.size() == 1) {
+ offsets.emplace_back(offset);
+ dimensions.emplace_back(static_cast<int32_t>(properties.dimension));
+ sizes.emplace_back(static_cast<int32_t>(properties.size));
+ samplingKeys.emplace_back(static_cast<int32_t>(properties.samplingKeys[0]));
+ }
+ }
+ hwcState.luts = std::make_shared<gui::DisplayLuts>(base::unique_fd(lutFileDescriptor.release()),
+ std::move(offsets), std::move(dimensions),
+ std::move(sizes), std::move(samplingKeys));
}
bool OutputLayer::needsFiltering() const {
diff --git a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
index 639164d..3e0c390 100644
--- a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
@@ -26,11 +26,8 @@
#include <gtest/gtest.h>
#include <renderengine/mock/RenderEngine.h>
-#include "MockHWComposer.h"
#include "TimeStats/TimeStats.h"
-#include "gmock/gmock.h"
-
-#include <variant>
+#include "mock/DisplayHardware/MockHWComposer.h"
using namespace com::android::graphics::surfaceflinger;
@@ -494,9 +491,6 @@
};
TEST_F(CompositionEnginePostCompositionTest, postCompositionReleasesAllFences) {
- SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::ce_fence_promise, true);
- ASSERT_TRUE(FlagManager::getInstance().ce_fence_promise());
-
EXPECT_CALL(*mLayer1FE, getReleaseFencePromiseStatus)
.WillOnce(Return(LayerFE::ReleaseFencePromiseStatus::FULFILLED));
EXPECT_CALL(*mLayer2FE, getReleaseFencePromiseStatus)
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 9c0e62c..416001e 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -36,10 +36,10 @@
#include <ui/Rect.h>
#include <ui/StaticDisplayInfo.h>
-#include "MockHWC2.h"
-#include "MockHWComposer.h"
-#include "MockPowerAdvisor.h"
#include "ftl/future.h"
+#include "mock/DisplayHardware/MockHWC2.h"
+#include "mock/DisplayHardware/MockHWComposer.h"
+#include "mock/DisplayHardware/MockPowerAdvisor.h"
#include <aidl/android/hardware/graphics/composer3/Composition.h>
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.cpp b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.cpp
deleted file mode 100644
index 0baa79d..0000000
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2019 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 "MockHWC2.h"
-
-namespace android::HWC2 {
-
-// This will go away once HWC2::Layer is moved into the "backend" library
-Layer::~Layer() = default;
-
-namespace mock {
-
-// The Google Mock documentation recommends explicit non-header instantiations
-// for better compile time performance.
-Layer::Layer() = default;
-Layer::~Layer() = default;
-
-} // namespace mock
-} // namespace android::HWC2
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
deleted file mode 100644
index eb6e677..0000000
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2019 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 <gmock/gmock.h>
-#include <ui/Fence.h>
-#include <ui/FloatRect.h>
-#include <ui/GraphicBuffer.h>
-#include <ui/Rect.h>
-#include <ui/Region.h>
-#include <ui/Transform.h>
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-#pragma clang diagnostic ignored "-Wextra"
-
-#include <ui/GraphicTypes.h>
-#include "DisplayHardware/HWC2.h"
-
-#include <aidl/android/hardware/graphics/composer3/Composition.h>
-#include <aidl/android/hardware/graphics/composer3/Lut.h>
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
-
-namespace android {
-namespace HWC2 {
-namespace mock {
-
-namespace hal = android::hardware::graphics::composer::hal;
-
-using Error = hal::Error;
-
-class Layer : public HWC2::Layer {
-public:
- Layer();
- ~Layer() override;
-
- MOCK_CONST_METHOD0(getId, hal::HWLayerId());
-
- MOCK_METHOD2(setCursorPosition, Error(int32_t, int32_t));
- MOCK_METHOD3(setBuffer,
- Error(uint32_t, const android::sp<android::GraphicBuffer>&,
- const android::sp<android::Fence>&));
- MOCK_METHOD2(setBufferSlotsToClear, Error(const std::vector<uint32_t>&, uint32_t));
- MOCK_METHOD1(setSurfaceDamage, Error(const android::Region&));
- MOCK_METHOD1(setBlendMode, Error(hal::BlendMode));
- MOCK_METHOD1(setColor, Error(aidl::android::hardware::graphics::composer3::Color));
- MOCK_METHOD1(setCompositionType,
- Error(aidl::android::hardware::graphics::composer3::Composition));
- MOCK_METHOD1(setDataspace, Error(android::ui::Dataspace));
- MOCK_METHOD2(setPerFrameMetadata, Error(const int32_t, const android::HdrMetadata&));
- MOCK_METHOD1(setDisplayFrame, Error(const android::Rect&));
- MOCK_METHOD1(setPlaneAlpha, Error(float));
- MOCK_METHOD1(setSidebandStream, Error(const native_handle_t*));
- MOCK_METHOD1(setSourceCrop, Error(const android::FloatRect&));
- MOCK_METHOD1(setTransform, Error(hal::Transform));
- MOCK_METHOD1(setVisibleRegion, Error(const android::Region&));
- MOCK_METHOD1(setZOrder, Error(uint32_t));
-
- MOCK_METHOD1(setColorTransform, Error(const android::mat4&));
- MOCK_METHOD3(setLayerGenericMetadata,
- Error(const std::string&, bool, const std::vector<uint8_t>&));
- MOCK_METHOD1(setBrightness, Error(float));
- MOCK_METHOD1(setBlockingRegion, Error(const android::Region&));
- MOCK_METHOD(Error, setLuts, (std::vector<aidl::android::hardware::graphics::composer3::Lut>&));
-};
-
-} // namespace mock
-} // namespace HWC2
-} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
deleted file mode 100644
index 5c55ce7..0000000
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright 2018 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 <compositionengine/Output.h>
-#include <gmock/gmock.h>
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-#pragma clang diagnostic ignored "-Wextra"
-
-#include "DisplayHardware/HWComposer.h"
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
-
-namespace android {
-namespace mock {
-
-namespace hal = android::hardware::graphics::composer::hal;
-
-class HWComposer : public android::HWComposer {
-public:
- HWComposer();
- ~HWComposer() override;
-
- MOCK_METHOD1(setCallback, void(HWC2::ComposerCallback&));
- MOCK_CONST_METHOD3(getDisplayIdentificationData,
- bool(hal::HWDisplayId, uint8_t*, DisplayIdentificationData*));
- MOCK_CONST_METHOD1(hasCapability,
- bool(aidl::android::hardware::graphics::composer3::Capability));
- MOCK_CONST_METHOD2(hasDisplayCapability,
- bool(HalDisplayId,
- aidl::android::hardware::graphics::composer3::DisplayCapability));
-
- MOCK_CONST_METHOD0(getMaxVirtualDisplayCount, size_t());
- MOCK_CONST_METHOD0(getMaxVirtualDisplayDimension, size_t());
- MOCK_METHOD3(allocateVirtualDisplay, bool(HalVirtualDisplayId, ui::Size, ui::PixelFormat*));
- MOCK_METHOD3(allocatePhysicalDisplay,
- void(hal::HWDisplayId, PhysicalDisplayId, std::optional<ui::Size>));
-
- MOCK_METHOD1(createLayer, std::shared_ptr<HWC2::Layer>(HalDisplayId));
- MOCK_METHOD(status_t, getDeviceCompositionChanges,
- (HalDisplayId, bool, std::optional<std::chrono::steady_clock::time_point>, nsecs_t,
- Fps, std::optional<android::HWComposer::DeviceRequestedChanges>*));
- MOCK_METHOD(status_t, setClientTarget,
- (HalDisplayId, uint32_t, const sp<Fence>&, const sp<GraphicBuffer>&, ui::Dataspace,
- float),
- (override));
- MOCK_METHOD2(presentAndGetReleaseFences,
- status_t(HalDisplayId, std::optional<std::chrono::steady_clock::time_point>));
- MOCK_METHOD(status_t, executeCommands, (HalDisplayId));
- MOCK_METHOD2(setPowerMode, status_t(PhysicalDisplayId, hal::PowerMode));
- MOCK_METHOD2(setActiveConfig, status_t(HalDisplayId, size_t));
- MOCK_METHOD2(setColorTransform, status_t(HalDisplayId, const mat4&));
- MOCK_METHOD1(disconnectDisplay, void(HalDisplayId));
- MOCK_CONST_METHOD1(hasDeviceComposition, bool(const std::optional<DisplayId>&));
- MOCK_CONST_METHOD1(getPresentFence, sp<Fence>(HalDisplayId));
- MOCK_METHOD(nsecs_t, getPresentTimestamp, (PhysicalDisplayId), (const, override));
- MOCK_CONST_METHOD2(getLayerReleaseFence, sp<Fence>(HalDisplayId, HWC2::Layer*));
- MOCK_METHOD3(setOutputBuffer,
- status_t(HalVirtualDisplayId, const sp<Fence>&, const sp<GraphicBuffer>&));
- MOCK_METHOD1(clearReleaseFences, void(HalDisplayId));
- MOCK_METHOD2(getHdrCapabilities, status_t(HalDisplayId, HdrCapabilities*));
- MOCK_CONST_METHOD1(getSupportedPerFrameMetadata, int32_t(HalDisplayId));
- MOCK_CONST_METHOD2(getRenderIntents,
- std::vector<ui::RenderIntent>(HalDisplayId, ui::ColorMode));
- MOCK_METHOD2(getDataspaceSaturationMatrix, mat4(HalDisplayId, ui::Dataspace));
- MOCK_METHOD4(getDisplayedContentSamplingAttributes,
- status_t(HalDisplayId, ui::PixelFormat*, ui::Dataspace*, uint8_t*));
- MOCK_METHOD4(setDisplayContentSamplingEnabled, status_t(HalDisplayId, bool, uint8_t, uint64_t));
- MOCK_METHOD4(getDisplayedContentSample,
- status_t(HalDisplayId, uint64_t, uint64_t, DisplayedFrameStats*));
- MOCK_METHOD(ftl::Future<status_t>, setDisplayBrightness,
- (PhysicalDisplayId, float, float, const Hwc2::Composer::DisplayBrightnessOptions&),
- (override));
- MOCK_METHOD2(getDisplayBrightnessSupport, status_t(PhysicalDisplayId, bool*));
-
- MOCK_METHOD2(onHotplug,
- std::optional<DisplayIdentificationInfo>(hal::HWDisplayId, hal::Connection));
- MOCK_CONST_METHOD0(updatesDeviceProductInfoOnHotplugReconnect, bool());
- MOCK_METHOD(std::optional<PhysicalDisplayId>, onVsync, (hal::HWDisplayId, int64_t));
- MOCK_METHOD2(setVsyncEnabled, void(PhysicalDisplayId, hal::Vsync));
- MOCK_CONST_METHOD1(isConnected, bool(PhysicalDisplayId));
- MOCK_CONST_METHOD2(getModes,
- std::vector<HWComposer::HWCDisplayMode>(PhysicalDisplayId, int32_t));
- MOCK_CONST_METHOD1(getActiveMode, ftl::Expected<hal::HWConfigId, status_t>(PhysicalDisplayId));
- MOCK_CONST_METHOD1(getColorModes, std::vector<ui::ColorMode>(PhysicalDisplayId));
- MOCK_METHOD3(setActiveColorMode, status_t(PhysicalDisplayId, ui::ColorMode, ui::RenderIntent));
- MOCK_CONST_METHOD0(isUsingVrComposer, bool());
- MOCK_CONST_METHOD1(getDisplayConnectionType, ui::DisplayConnectionType(PhysicalDisplayId));
- MOCK_CONST_METHOD1(isVsyncPeriodSwitchSupported, bool(PhysicalDisplayId));
- MOCK_CONST_METHOD1(getDisplayVsyncPeriod, ftl::Expected<nsecs_t, status_t>(PhysicalDisplayId));
- MOCK_METHOD4(setActiveModeWithConstraints,
- status_t(PhysicalDisplayId, hal::HWConfigId,
- const hal::VsyncPeriodChangeConstraints&,
- hal::VsyncPeriodChangeTimeline*));
- MOCK_METHOD2(setBootDisplayMode, status_t(PhysicalDisplayId, hal::HWConfigId));
- MOCK_METHOD1(clearBootDisplayMode, status_t(PhysicalDisplayId));
- MOCK_METHOD1(getPreferredBootDisplayMode, std::optional<hal::HWConfigId>(PhysicalDisplayId));
- MOCK_METHOD0(getBootDisplayModeSupport, bool());
- MOCK_CONST_METHOD0(
- getHdrConversionCapabilities,
- std::vector<aidl::android::hardware::graphics::common::HdrConversionCapability>());
- MOCK_METHOD2(setHdrConversionStrategy,
- status_t(aidl::android::hardware::graphics::common::HdrConversionStrategy,
- aidl::android::hardware::graphics::common::Hdr*));
- MOCK_METHOD2(setAutoLowLatencyMode, status_t(PhysicalDisplayId, bool));
- MOCK_METHOD(status_t, getSupportedContentTypes,
- (PhysicalDisplayId, std::vector<hal::ContentType>*), (const, override));
- MOCK_METHOD2(setContentType, status_t(PhysicalDisplayId, hal::ContentType));
- MOCK_CONST_METHOD0(getSupportedLayerGenericMetadata,
- const std::unordered_map<std::string, bool>&());
-
- MOCK_CONST_METHOD1(dump, void(std::string&));
- MOCK_CONST_METHOD1(dumpOverlayProperties, void(std::string&));
- MOCK_CONST_METHOD0(getComposer, android::Hwc2::Composer*());
-
- MOCK_METHOD(hal::HWDisplayId, getPrimaryHwcDisplayId, (), (const, override));
- MOCK_METHOD(PhysicalDisplayId, getPrimaryDisplayId, (), (const, override));
- MOCK_METHOD(bool, isHeadless, (), (const, override));
-
- MOCK_METHOD(std::optional<PhysicalDisplayId>, toPhysicalDisplayId, (hal::HWDisplayId),
- (const, override));
- MOCK_METHOD(std::optional<hal::HWDisplayId>, fromPhysicalDisplayId, (PhysicalDisplayId),
- (const, override));
- MOCK_METHOD2(getDisplayDecorationSupport,
- status_t(PhysicalDisplayId,
- std::optional<aidl::android::hardware::graphics::common::
- DisplayDecorationSupport>* support));
- MOCK_METHOD2(setIdleTimerEnabled, status_t(PhysicalDisplayId, std::chrono::milliseconds));
- MOCK_METHOD(bool, hasDisplayIdleTimerCapability, (PhysicalDisplayId), (const, override));
- MOCK_METHOD(Hwc2::AidlTransform, getPhysicalDisplayOrientation, (PhysicalDisplayId),
- (const, override));
- MOCK_METHOD(bool, getValidateSkipped, (HalDisplayId), (const, override));
- MOCK_METHOD(const aidl::android::hardware::graphics::composer3::OverlayProperties&,
- getOverlaySupport, (), (const, override));
- MOCK_METHOD(status_t, setRefreshRateChangedCallbackDebugEnabled, (PhysicalDisplayId, bool));
- MOCK_METHOD(status_t, notifyExpectedPresent, (PhysicalDisplayId, TimePoint, Fps));
- MOCK_METHOD((HWC2::Display::LutFileDescriptorMapper&), getLutFileDescriptorMapper, (), ());
-};
-
-} // namespace mock
-} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.cpp b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.cpp
deleted file mode 100644
index 85b9403..0000000
--- a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2019 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 "MockPowerAdvisor.h"
-
-namespace android {
-namespace Hwc2 {
-
-// This will go away once PowerAdvisor is moved into the "backend" library
-PowerAdvisor::~PowerAdvisor() = default;
-
-namespace mock {
-
-// The Google Mock documentation recommends explicit non-header instantiations
-// for better compile time performance.
-PowerAdvisor::PowerAdvisor() = default;
-PowerAdvisor::~PowerAdvisor() = default;
-
-} // namespace mock
-} // namespace Hwc2
-} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
deleted file mode 100644
index ed2ffa9..0000000
--- a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2019 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 <gmock/gmock.h>
-
-#include "DisplayHardware/PowerAdvisor.h"
-
-namespace android {
-namespace Hwc2 {
-namespace mock {
-
-class PowerAdvisor : public android::Hwc2::PowerAdvisor {
-public:
- PowerAdvisor();
- ~PowerAdvisor() override;
-
- MOCK_METHOD(void, init, (), (override));
- MOCK_METHOD(void, onBootFinished, (), (override));
- MOCK_METHOD(void, setExpensiveRenderingExpected, (DisplayId displayId, bool expected),
- (override));
- MOCK_METHOD(bool, isUsingExpensiveRendering, (), (override));
- MOCK_METHOD(void, notifyCpuLoadUp, (), (override));
- MOCK_METHOD(void, notifyDisplayUpdateImminentAndCpuReset, (), (override));
- MOCK_METHOD(bool, usePowerHintSession, (), (override));
- MOCK_METHOD(bool, supportsPowerHintSession, (), (override));
- MOCK_METHOD(bool, supportsGpuReporting, (), (override));
- MOCK_METHOD(void, updateTargetWorkDuration, (Duration targetDuration), (override));
- MOCK_METHOD(void, reportActualWorkDuration, (), (override));
- MOCK_METHOD(void, enablePowerHintSession, (bool enabled), (override));
- MOCK_METHOD(bool, startPowerHintSession, (std::vector<int32_t> && threadIds), (override));
- MOCK_METHOD(void, setGpuStartTime, (DisplayId displayId, TimePoint startTime), (override));
- MOCK_METHOD(void, setGpuFenceTime,
- (DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime), (override));
- MOCK_METHOD(void, setHwcValidateTiming,
- (DisplayId displayId, TimePoint validateStartTime, TimePoint validateEndTime),
- (override));
- MOCK_METHOD(void, setHwcPresentTiming,
- (DisplayId displayId, TimePoint presentStartTime, TimePoint presentEndTime),
- (override));
- MOCK_METHOD(void, setSkippedValidate, (DisplayId displayId, bool skipped), (override));
- MOCK_METHOD(void, setRequiresRenderEngine, (DisplayId displayId, bool requiresRenderEngine),
- (override));
- MOCK_METHOD(void, setExpectedPresentTime, (TimePoint expectedPresentTime), (override));
- MOCK_METHOD(void, setSfPresentTiming, (TimePoint presentFenceTime, TimePoint presentEndTime),
- (override));
- MOCK_METHOD(void, setHwcPresentDelayedTime,
- (DisplayId displayId, TimePoint earliestFrameStartTime));
- MOCK_METHOD(void, setFrameDelay, (Duration frameDelayDuration), (override));
- MOCK_METHOD(void, setCommitStart, (TimePoint commitStartTime), (override));
- MOCK_METHOD(void, setCompositeEnd, (TimePoint compositeEndTime), (override));
- MOCK_METHOD(void, setDisplays, (std::vector<DisplayId> & displayIds), (override));
- MOCK_METHOD(void, setTotalFrameTargetWorkDuration, (Duration targetDuration), (override));
-};
-
-} // namespace mock
-} // namespace Hwc2
-} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index b21533a..f2c5672 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -23,14 +23,14 @@
#include <compositionengine/mock/Output.h>
#include <gtest/gtest.h>
#include <log/log.h>
-
#include <renderengine/impl/ExternalTexture.h>
#include <renderengine/mock/RenderEngine.h>
+#include <ui/FloatRect.h>
#include <ui/PixelFormat.h>
-#include "MockHWC2.h"
-#include "MockHWComposer.h"
+
#include "RegionMatcher.h"
-#include "ui/FloatRect.h"
+#include "mock/DisplayHardware/MockHWC2.h"
+#include "mock/DisplayHardware/MockHWComposer.h"
#include <aidl/android/hardware/graphics/composer3/Composition.h>
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index c34168d..fe7dd9a 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -34,15 +34,14 @@
#include <ui/Rect.h>
#include <ui/Region.h>
-#include <cmath>
#include <cstdint>
#include <variant>
#include <common/FlagManager.h>
#include <common/test/FlagUtils.h>
#include "CallOrderStateMachineHelper.h"
-#include "MockHWC2.h"
#include "RegionMatcher.h"
+#include "mock/DisplayHardware/MockHWC2.h"
namespace android::compositionengine {
namespace {
@@ -786,17 +785,20 @@
InjectedLayer layer3;
uint32_t z = 0;
- EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180));
+ EXPECT_CALL(*layer1.outputLayer,
+ updateCompositionState(false, false, ui::Transform::ROT_180, _));
EXPECT_CALL(*layer1.outputLayer,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false));
- EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180));
+ EXPECT_CALL(*layer2.outputLayer,
+ updateCompositionState(false, false, ui::Transform::ROT_180, _));
EXPECT_CALL(*layer2.outputLayer,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false));
- EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180));
+ EXPECT_CALL(*layer3.outputLayer,
+ updateCompositionState(false, false, ui::Transform::ROT_180, _));
EXPECT_CALL(*layer3.outputLayer,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
@@ -823,17 +825,17 @@
InjectedLayer layer3;
uint32_t z = 0;
- EXPECT_CALL(*layer1.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
+ EXPECT_CALL(*layer1.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _));
EXPECT_CALL(*layer1.outputLayer,
writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false));
- EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
+ EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _));
EXPECT_CALL(*layer2.outputLayer,
writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false));
- EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
+ EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _));
EXPECT_CALL(*layer3.outputLayer,
writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
@@ -859,17 +861,17 @@
InjectedLayer layer3;
uint32_t z = 0;
- EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
+ EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _));
EXPECT_CALL(*layer1.outputLayer,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false));
- EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
+ EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _));
EXPECT_CALL(*layer2.outputLayer,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false));
- EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
+ EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _));
EXPECT_CALL(*layer3.outputLayer,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
@@ -897,11 +899,11 @@
InjectedLayer layer3;
InSequence seq;
- EXPECT_CALL(*layer0.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
- EXPECT_CALL(*layer1.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
+ EXPECT_CALL(*layer0.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _));
+ EXPECT_CALL(*layer1.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _));
EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false));
- EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
- EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
+ EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _));
+ EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _));
uint32_t z = 0;
EXPECT_CALL(*layer0.outputLayer,
@@ -3263,57 +3265,9 @@
mOutput.presentFrameAndReleaseLayers(kFlushEvenWhenDisabled);
}
-TEST_F(OutputPostFramebufferTest, releaseFencesAreSentToLayerFE) {
- SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::ce_fence_promise, false);
- ASSERT_FALSE(FlagManager::getInstance().ce_fence_promise());
- // Simulate getting release fences from each layer, and ensure they are passed to the
- // front-end layer interface for each layer correctly.
-
- mOutput.mState.isEnabled = true;
-
- // Create three unique fence instances
- sp<Fence> layer1Fence = sp<Fence>::make();
- sp<Fence> layer2Fence = sp<Fence>::make();
- sp<Fence> layer3Fence = sp<Fence>::make();
-
- Output::FrameFences frameFences;
- frameFences.layerFences.emplace(&mLayer1.hwc2Layer, layer1Fence);
- frameFences.layerFences.emplace(&mLayer2.hwc2Layer, layer2Fence);
- frameFences.layerFences.emplace(&mLayer3.hwc2Layer, layer3Fence);
-
- EXPECT_CALL(mOutput, presentFrame()).WillOnce(Return(frameFences));
- EXPECT_CALL(*mRenderSurface, onPresentDisplayCompleted());
-
- // Compare the pointers values of each fence to make sure the correct ones
- // are passed. This happens to work with the current implementation, but
- // would not survive certain calls like Fence::merge() which would return a
- // new instance.
- EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed(_, _))
- .WillOnce([&layer1Fence](ftl::SharedFuture<FenceResult> futureFenceResult,
- ui::LayerStack) {
- EXPECT_EQ(FenceResult(layer1Fence), futureFenceResult.get());
- });
- EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed(_, _))
- .WillOnce([&layer2Fence](ftl::SharedFuture<FenceResult> futureFenceResult,
- ui::LayerStack) {
- EXPECT_EQ(FenceResult(layer2Fence), futureFenceResult.get());
- });
- EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed(_, _))
- .WillOnce([&layer3Fence](ftl::SharedFuture<FenceResult> futureFenceResult,
- ui::LayerStack) {
- EXPECT_EQ(FenceResult(layer3Fence), futureFenceResult.get());
- });
-
- constexpr bool kFlushEvenWhenDisabled = false;
- mOutput.presentFrameAndReleaseLayers(kFlushEvenWhenDisabled);
-}
-
TEST_F(OutputPostFramebufferTest, releaseFencesAreSetInLayerFE) {
- SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::ce_fence_promise, true);
- ASSERT_TRUE(FlagManager::getInstance().ce_fence_promise());
// Simulate getting release fences from each layer, and ensure they are passed to the
// front-end layer interface for each layer correctly.
-
mOutput.mState.isEnabled = true;
// Create three unique fence instances
@@ -3350,37 +3304,7 @@
mOutput.presentFrameAndReleaseLayers(kFlushEvenWhenDisabled);
}
-TEST_F(OutputPostFramebufferTest, releaseFencesIncludeClientTargetAcquireFence) {
- SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::ce_fence_promise, false);
- ASSERT_FALSE(FlagManager::getInstance().ce_fence_promise());
-
- mOutput.mState.isEnabled = true;
- mOutput.mState.usesClientComposition = true;
-
- Output::FrameFences frameFences;
- frameFences.clientTargetAcquireFence = sp<Fence>::make();
- frameFences.layerFences.emplace(&mLayer1.hwc2Layer, sp<Fence>::make());
- frameFences.layerFences.emplace(&mLayer2.hwc2Layer, sp<Fence>::make());
- frameFences.layerFences.emplace(&mLayer3.hwc2Layer, sp<Fence>::make());
-
- EXPECT_CALL(mOutput, presentFrame()).WillOnce(Return(frameFences));
- EXPECT_CALL(*mRenderSurface, onPresentDisplayCompleted());
-
- // Fence::merge is called, and since none of the fences are actually valid,
- // Fence::NO_FENCE is returned and passed to each onLayerDisplayed() call.
- // This is the best we can do without creating a real kernel fence object.
- EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed).WillOnce(Return());
- EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed).WillOnce(Return());
- EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed).WillOnce(Return());
-
- constexpr bool kFlushEvenWhenDisabled = false;
- mOutput.presentFrameAndReleaseLayers(kFlushEvenWhenDisabled);
-}
-
TEST_F(OutputPostFramebufferTest, setReleaseFencesIncludeClientTargetAcquireFence) {
- SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::ce_fence_promise, true);
- ASSERT_TRUE(FlagManager::getInstance().ce_fence_promise());
-
mOutput.mState.isEnabled = true;
mOutput.mState.usesClientComposition = true;
@@ -3403,62 +3327,7 @@
mOutput.presentFrameAndReleaseLayers(kFlushEvenWhenDisabled);
}
-TEST_F(OutputPostFramebufferTest, releasedLayersSentPresentFence) {
- SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::ce_fence_promise, false);
- ASSERT_FALSE(FlagManager::getInstance().ce_fence_promise());
-
- mOutput.mState.isEnabled = true;
- mOutput.mState.usesClientComposition = true;
-
- // This should happen even if there are no (current) output layers.
- EXPECT_CALL(mOutput, getOutputLayerCount()).WillOnce(Return(0u));
-
- // Load up the released layers with some mock instances
- sp<StrictMock<mock::LayerFE>> releasedLayer1 = sp<StrictMock<mock::LayerFE>>::make();
- sp<StrictMock<mock::LayerFE>> releasedLayer2 = sp<StrictMock<mock::LayerFE>>::make();
- sp<StrictMock<mock::LayerFE>> releasedLayer3 = sp<StrictMock<mock::LayerFE>>::make();
- Output::ReleasedLayers layers;
- layers.push_back(releasedLayer1);
- layers.push_back(releasedLayer2);
- layers.push_back(releasedLayer3);
- mOutput.setReleasedLayers(std::move(layers));
-
- // Set up a fake present fence
- sp<Fence> presentFence = sp<Fence>::make();
- Output::FrameFences frameFences;
- frameFences.presentFence = presentFence;
-
- EXPECT_CALL(mOutput, presentFrame()).WillOnce(Return(frameFences));
- EXPECT_CALL(*mRenderSurface, onPresentDisplayCompleted());
-
- // Each released layer should be given the presentFence.
- EXPECT_CALL(*releasedLayer1, onLayerDisplayed(_, _))
- .WillOnce([&presentFence](ftl::SharedFuture<FenceResult> futureFenceResult,
- ui::LayerStack) {
- EXPECT_EQ(FenceResult(presentFence), futureFenceResult.get());
- });
- EXPECT_CALL(*releasedLayer2, onLayerDisplayed(_, _))
- .WillOnce([&presentFence](ftl::SharedFuture<FenceResult> futureFenceResult,
- ui::LayerStack) {
- EXPECT_EQ(FenceResult(presentFence), futureFenceResult.get());
- });
- EXPECT_CALL(*releasedLayer3, onLayerDisplayed(_, _))
- .WillOnce([&presentFence](ftl::SharedFuture<FenceResult> futureFenceResult,
- ui::LayerStack) {
- EXPECT_EQ(FenceResult(presentFence), futureFenceResult.get());
- });
-
- constexpr bool kFlushEvenWhenDisabled = false;
- mOutput.presentFrameAndReleaseLayers(kFlushEvenWhenDisabled);
-
- // After the call the list of released layers should have been cleared.
- EXPECT_TRUE(mOutput.getReleasedLayersForTest().empty());
-}
-
TEST_F(OutputPostFramebufferTest, setReleasedLayersSentPresentFence) {
- SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::ce_fence_promise, true);
- ASSERT_TRUE(FlagManager::getInstance().ce_fence_promise());
-
mOutput.mState.isEnabled = true;
mOutput.mState.usesClientComposition = true;
@@ -5066,12 +4935,12 @@
uint32_t z = 0;
// Layer requesting blur, or below, should request client composition, unless opaque.
- EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0));
+ EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0, _));
EXPECT_CALL(*layer1.outputLayer,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false));
- EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0));
+ EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0, _));
EXPECT_CALL(*layer2.outputLayer,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
@@ -5100,17 +4969,17 @@
uint32_t z = 0;
// Layer requesting blur, or below, should request client composition.
- EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
+ EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _));
EXPECT_CALL(*layer1.outputLayer,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false));
- EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
+ EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _));
EXPECT_CALL(*layer2.outputLayer,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false));
- EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0));
+ EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0, _));
EXPECT_CALL(*layer3.outputLayer,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
@@ -5140,17 +5009,17 @@
uint32_t z = 0;
// Layer requesting blur, or below, should request client composition.
- EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
+ EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _));
EXPECT_CALL(*layer1.outputLayer,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false));
- EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
+ EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _));
EXPECT_CALL(*layer2.outputLayer,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false));
- EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0));
+ EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0, _));
EXPECT_CALL(*layer3.outputLayer,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index 77bd804..5814aa4 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -44,7 +44,7 @@
using aidl::android::hardware::graphics::composer3::BnComposerCallback;
using aidl::android::hardware::graphics::composer3::Capability;
using aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness;
-using aidl::android::hardware::graphics::composer3::Lut;
+using aidl::android::hardware::graphics::composer3::Luts;
using aidl::android::hardware::graphics::composer3::PowerMode;
using aidl::android::hardware::graphics::composer3::VirtualDisplay;
@@ -1565,7 +1565,7 @@
return error;
}
-Error AidlComposer::setLayerLuts(Display display, Layer layer, std::vector<Lut>& luts) {
+Error AidlComposer::setLayerLuts(Display display, Layer layer, Luts& luts) {
Error error = Error::NONE;
mMutex.lock_shared();
if (auto writer = getWriter(display)) {
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
index cdb67e4..d724b21 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
@@ -53,6 +53,7 @@
using aidl::android::hardware::graphics::common::HdrConversionStrategy;
using aidl::android::hardware::graphics::composer3::ComposerClientReader;
using aidl::android::hardware::graphics::composer3::ComposerClientWriter;
+using aidl::android::hardware::graphics::composer3::Luts;
using aidl::android::hardware::graphics::composer3::OverlayProperties;
class AidlIComposerCallbackWrapper;
@@ -248,9 +249,7 @@
Display display, std::vector<Layer>* outLayers,
std::vector<aidl::android::hardware::graphics::composer3::DisplayLuts::LayerLut>*
outLuts) override;
- Error setLayerLuts(
- Display display, Layer layer,
- std::vector<aidl::android::hardware::graphics::composer3::Lut>& luts) override;
+ Error setLayerLuts(Display display, Layer layer, Luts& luts) override;
private:
// Many public functions above simply write a command into the command
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 0905663..42ddcd1 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -42,7 +42,6 @@
#include <aidl/android/hardware/graphics/composer3/DisplayConfiguration.h>
#include <aidl/android/hardware/graphics/composer3/DisplayLuts.h>
#include <aidl/android/hardware/graphics/composer3/IComposerCallback.h>
-#include <aidl/android/hardware/graphics/composer3/Lut.h>
#include <aidl/android/hardware/graphics/composer3/OverlayProperties.h>
#include <aidl/android/hardware/graphics/common/Transform.h>
@@ -307,7 +306,7 @@
int32_t frameIntervalNs) = 0;
virtual Error getRequestedLuts(Display display, std::vector<Layer>* outLayers,
std::vector<V3_0::DisplayLuts::LayerLut>* outLuts) = 0;
- virtual Error setLayerLuts(Display display, Layer layer, std::vector<V3_0::Lut>& luts) = 0;
+ virtual Error setLayerLuts(Display display, Layer layer, V3_0::Luts& luts) = 0;
};
} // namespace Hwc2
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 1df2ab1..5355a12 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -42,7 +42,8 @@
using AidlCapability = aidl::android::hardware::graphics::composer3::Capability;
using aidl::android::hardware::graphics::composer3::DisplayCapability;
using aidl::android::hardware::graphics::composer3::DisplayLuts;
-using aidl::android::hardware::graphics::composer3::Lut;
+using aidl::android::hardware::graphics::composer3::LutProperties;
+using aidl::android::hardware::graphics::composer3::Luts;
using aidl::android::hardware::graphics::composer3::OverlayProperties;
namespace android {
@@ -624,10 +625,18 @@
auto layer = getLayerById(layerIds[i]);
if (layer) {
auto& layerLut = tmpLuts[i];
- outLuts->emplace_or_replace(layer.get(), layerLut.lut.lutProperties);
- lutFileDescriptorMapper.emplace_or_replace(layer.get(),
- ndk::ScopedFileDescriptor(
- layerLut.lut.pfd.release()));
+ if (layerLut.luts.pfd.get() > 0 && layerLut.luts.offsets.has_value()) {
+ const auto& offsets = layerLut.luts.offsets.value();
+ std::vector<std::pair<int32_t, LutProperties>> lutOffsetsAndProperties;
+ lutOffsetsAndProperties.reserve(offsets.size());
+ std::transform(offsets.begin(), offsets.end(), layerLut.luts.lutProperties.begin(),
+ std::back_inserter(lutOffsetsAndProperties),
+ [](int32_t i, LutProperties j) { return std::make_pair(i, j); });
+ outLuts->emplace_or_replace(layer.get(), lutOffsetsAndProperties);
+ lutFileDescriptorMapper.emplace_or_replace(layer.get(),
+ ndk::ScopedFileDescriptor(
+ layerLut.luts.pfd.release()));
+ }
}
}
@@ -1069,7 +1078,7 @@
return static_cast<Error>(intError);
}
-Error Layer::setLuts(std::vector<Lut>& luts) {
+Error Layer::setLuts(aidl::android::hardware::graphics::composer3::Luts& luts) {
if (CC_UNLIKELY(!mDisplay)) {
return Error::BAD_DISPLAY;
}
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 61f92f4..799fd02 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -46,7 +46,7 @@
#include <aidl/android/hardware/graphics/composer3/Color.h>
#include <aidl/android/hardware/graphics/composer3/Composition.h>
#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
-#include <aidl/android/hardware/graphics/composer3/Lut.h>
+#include <aidl/android/hardware/graphics/composer3/Luts.h>
#include <aidl/android/hardware/graphics/composer3/OverlayProperties.h>
#include <aidl/android/hardware/graphics/composer3/RefreshRateChangedDebugData.h>
@@ -109,9 +109,10 @@
virtual std::optional<ui::Size> getPhysicalSizeInMm() const = 0;
static const int kLutFileDescriptorMapperSize = 20;
+ using LutOffsetAndProperties = std::vector<
+ std::pair<int32_t, aidl::android::hardware::graphics::composer3::LutProperties>>;
using LayerLuts =
- ftl::SmallMap<HWC2::Layer*, aidl::android::hardware::graphics::composer3::LutProperties,
- kLutFileDescriptorMapperSize>;
+ ftl::SmallMap<HWC2::Layer*, LutOffsetAndProperties, kLutFileDescriptorMapperSize>;
using LutFileDescriptorMapper =
ftl::SmallMap<HWC2::Layer*, ndk::ScopedFileDescriptor, kLutFileDescriptorMapperSize>;
@@ -375,7 +376,7 @@
[[nodiscard]] virtual hal::Error setBrightness(float brightness) = 0;
[[nodiscard]] virtual hal::Error setBlockingRegion(const android::Region& region) = 0;
[[nodiscard]] virtual hal::Error setLuts(
- std::vector<aidl::android::hardware::graphics::composer3::Lut>& luts) = 0;
+ aidl::android::hardware::graphics::composer3::Luts& luts) = 0;
};
namespace impl {
@@ -426,8 +427,7 @@
// AIDL HAL
hal::Error setBrightness(float brightness) override;
hal::Error setBlockingRegion(const android::Region& region) override;
- hal::Error setLuts(
- std::vector<aidl::android::hardware::graphics::composer3::Lut>& luts) override;
+ hal::Error setLuts(aidl::android::hardware::graphics::composer3::Luts&) override;
private:
// These are references to data owned by HWComposer, which will outlive
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index e37c0ba..7d77634 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -379,7 +379,7 @@
const int32_t dpiX = getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_X);
const int32_t dpiY = getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_Y);
const DisplayConfiguration::Dpi hwcDpi =
- DisplayConfiguration::Dpi{dpiX == -1 ? dpiY : dpiX / 1000.f,
+ DisplayConfiguration::Dpi{dpiX == -1 ? dpiX : dpiX / 1000.f,
dpiY == -1 ? dpiY : dpiY / 1000.f};
const DisplayConfiguration::Dpi estimatedDPI =
getEstimatedDotsPerInchFromSize(hwcDisplayId, hwcMode);
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index 056ecd7..6a7a09b 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -47,7 +47,7 @@
using aidl::android::hardware::graphics::composer3::DimmingStage;
using aidl::android::hardware::graphics::composer3::DisplayCapability;
using aidl::android::hardware::graphics::composer3::DisplayLuts;
-using aidl::android::hardware::graphics::composer3::Lut;
+using aidl::android::hardware::graphics::composer3::Luts;
using aidl::android::hardware::graphics::composer3::OverlayProperties;
namespace android {
@@ -1415,7 +1415,7 @@
return Error::NONE;
}
-Error HidlComposer::setLayerLuts(Display, Layer, std::vector<Lut>&) {
+Error HidlComposer::setLayerLuts(Display, Layer, Luts&) {
return Error::NONE;
}
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
index 1cc23d1..a3d1f7f 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
@@ -356,7 +356,7 @@
std::vector<aidl::android::hardware::graphics::composer3::DisplayLuts::LayerLut>*)
override;
Error setLayerLuts(Display, Layer,
- std::vector<aidl::android::hardware::graphics::composer3::Lut>&) override;
+ aidl::android::hardware::graphics::composer3::Luts&) override;
private:
class CommandWriter : public CommandWriterBase {
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 334c104..c914ec3 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -240,7 +240,8 @@
&mSessionConfig);
if (ret.isOk()) {
mHintSession = ret.value();
- if (FlagManager::getInstance().adpf_use_fmq_channel_fixed()) {
+ if (FlagManager::getInstance().adpf_use_fmq_channel_fixed() &&
+ FlagManager::getInstance().adpf_fmq_sf()) {
setUpFmq();
}
}
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
index e5f6b7b..11b674b 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
@@ -513,6 +513,10 @@
isOpaque = contentOpaque && !roundedCorner.hasRoundedCorners() && color.a == 1.f;
blendMode = getBlendMode(requested);
}
+
+ if (forceUpdate || requested.what & layer_state_t::eLutsChanged) {
+ luts = requested.luts;
+ }
}
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/FrontEnd/readme.md b/services/surfaceflinger/FrontEnd/readme.md
index e5f51a5..6258f7e 100644
--- a/services/surfaceflinger/FrontEnd/readme.md
+++ b/services/surfaceflinger/FrontEnd/readme.md
@@ -17,6 +17,29 @@
This allows control to be delegated to different parts of the system - such as SystemServer,
SysUI and Apps.
+### Layer Drawing Order
+Layers are drawn based on an inorder traversal, treating relative parents as
+direct parents. Negative z-values place layers below their parent, while
+non-negative values place them above. Layers with the same z-value are drawn
+in creation order (newer on top). However, relying on creation order for
+z-ordering is discouraged; use unique z-values whenever possible for better
+control.
+
+Traversal pseudo code:
+```
+fn traverseBottomToTop(root):
+ for each child node including relative children,
+ sorted by z then layer id, with z less than 0:
+ traverseBottomToTop(childNode)
+
+ visit(root)
+
+ for each child node including relative children,
+ sorted by z then layer id, with z greater than
+ or equal to 0:
+ traverseBottomToTop(childNode)
+```
+
### Layer Lifecycle
Layer is created by a client. The client receives a strong binder reference to the layer
handle, which will keep the layer alive as long as the client holds the reference. The
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index c14769e..c88092b 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -185,6 +185,14 @@
mFlinger->onLayerDestroyed(this);
+ const auto currentTime = std::chrono::steady_clock::now();
+ if (mBufferInfo.mTimeSinceDataspaceUpdate > std::chrono::steady_clock::time_point::min()) {
+ mFlinger->mLayerEvents.emplace_back(mOwnerUid, getSequence(), mBufferInfo.mDataspace,
+ std::chrono::duration_cast<std::chrono::milliseconds>(
+ currentTime -
+ mBufferInfo.mTimeSinceDataspaceUpdate));
+ }
+
if (mDrawingState.sidebandStream != nullptr) {
mFlinger->mTunnelModeEnabledReporter->decrementTunnelModeCount();
}
@@ -751,54 +759,6 @@
}
}
-void Layer::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFenceResult,
- ui::LayerStack layerStack,
- std::function<FenceResult(FenceResult)>&& continuation) {
- sp<CallbackHandle> ch = findCallbackHandle();
-
- if (!FlagManager::getInstance().screenshot_fence_preservation() && continuation) {
- futureFenceResult = ftl::Future(futureFenceResult).then(std::move(continuation)).share();
- }
-
- if (ch != nullptr) {
- ch->previousReleaseCallbackId = mPreviousReleaseCallbackId;
- ch->previousSharedReleaseFences.emplace_back(std::move(futureFenceResult));
- ch->name = mName;
- } else if (FlagManager::getInstance().screenshot_fence_preservation()) {
- // If we didn't get a release callback yet, e.g. some scenarios when capturing screenshots
- // asynchronously, then make sure we don't drop the fence.
- mPreviousReleaseFenceAndContinuations.emplace_back(std::move(futureFenceResult),
- std::move(continuation));
- std::vector<FenceAndContinuation> mergedFences;
- sp<Fence> prevFence = nullptr;
- // For a layer that's frequently screenshotted, try to merge fences to make sure we don't
- // grow unbounded.
- for (const auto& futureAndContinuation : mPreviousReleaseFenceAndContinuations) {
- auto result = futureAndContinuation.future.wait_for(0s);
- if (result != std::future_status::ready) {
- mergedFences.emplace_back(futureAndContinuation);
- continue;
- }
-
- mergeFence(getDebugName(),
- futureAndContinuation.chain().get().value_or(Fence::NO_FENCE), prevFence);
- }
- if (prevFence != nullptr) {
- mergedFences.emplace_back(ftl::yield(FenceResult(std::move(prevFence))).share());
- }
-
- mPreviousReleaseFenceAndContinuations.swap(mergedFences);
- }
-
- if (mBufferInfo.mBuffer) {
- mPreviouslyPresentedLayerStacks.push_back(layerStack);
- }
-
- if (mDrawingState.frameNumber > 0) {
- mDrawingState.previousFrameNumber = mDrawingState.frameNumber;
- }
-}
-
void Layer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
for (const auto& handle : mDrawingState.callbackHandles) {
handle->bufferReleaseChannel = mBufferReleaseChannel;
@@ -1111,22 +1071,13 @@
handle->acquireTimeOrFence = mCallbackHandleAcquireTimeOrFence;
handle->frameNumber = mDrawingState.frameNumber;
handle->previousFrameNumber = mDrawingState.previousFrameNumber;
- if (FlagManager::getInstance().ce_fence_promise() &&
- mPreviousReleaseBufferEndpoint == handle->listener) {
+ if (mPreviousReleaseBufferEndpoint == handle->listener) {
// Add fence from previous screenshot now so that it can be dispatched to the
// client.
for (auto& [_, future] : mAdditionalPreviousReleaseFences) {
handle->previousReleaseFences.emplace_back(std::move(future));
}
mAdditionalPreviousReleaseFences.clear();
- } else if (FlagManager::getInstance().screenshot_fence_preservation() &&
- mPreviousReleaseBufferEndpoint == handle->listener) {
- // Add fences from previous screenshots now so that they can be dispatched to the
- // client.
- for (const auto& futureAndContinution : mPreviousReleaseFenceAndContinuations) {
- handle->previousSharedReleaseFences.emplace_back(futureAndContinution.chain());
- }
- mPreviousReleaseFenceAndContinuations.clear();
}
// Store so latched time and release fence can be set
mDrawingState.callbackHandles.push_back(handle);
@@ -1318,8 +1269,17 @@
}
}
}
- if (lastDataspace != mBufferInfo.mDataspace) {
+ if (lastDataspace != mBufferInfo.mDataspace ||
+ mBufferInfo.mTimeSinceDataspaceUpdate == std::chrono::steady_clock::time_point::min()) {
mFlinger->mHdrLayerInfoChanged = true;
+ const auto currentTime = std::chrono::steady_clock::now();
+ if (mBufferInfo.mTimeSinceDataspaceUpdate > std::chrono::steady_clock::time_point::min()) {
+ mFlinger->mLayerEvents
+ .emplace_back(mOwnerUid, getSequence(), lastDataspace,
+ std::chrono::duration_cast<std::chrono::milliseconds>(
+ currentTime - mBufferInfo.mTimeSinceDataspaceUpdate));
+ }
+ mBufferInfo.mTimeSinceDataspaceUpdate = currentTime;
}
if (mBufferInfo.mDesiredHdrSdrRatio != mDrawingState.desiredHdrSdrRatio) {
mBufferInfo.mDesiredHdrSdrRatio = mDrawingState.desiredHdrSdrRatio;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index ce4b9c4..a2716c6 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -242,6 +242,8 @@
sp<Fence> mFence;
uint32_t mTransform{0};
ui::Dataspace mDataspace{ui::Dataspace::UNKNOWN};
+ std::chrono::steady_clock::time_point mTimeSinceDataspaceUpdate =
+ std::chrono::steady_clock::time_point::min();
Rect mCrop;
PixelFormat mPixelFormat{PIXEL_FORMAT_NONE};
bool mTransformToDisplayInverse{false};
@@ -257,8 +259,6 @@
bool fenceHasSignaled() const;
void onPreComposition(nsecs_t refreshStartTime);
- void onLayerDisplayed(ftl::SharedFuture<FenceResult>, ui::LayerStack layerStack,
- std::function<FenceResult(FenceResult)>&& continuation = nullptr);
// Tracks mLastClientCompositionFence and gets the callback handle for this layer.
sp<CallbackHandle> findCallbackHandle();
@@ -387,20 +387,6 @@
// from the layer.
std::vector<ui::LayerStack> mPreviouslyPresentedLayerStacks;
- struct FenceAndContinuation {
- ftl::SharedFuture<FenceResult> future;
- std::function<FenceResult(FenceResult)> continuation;
-
- ftl::SharedFuture<FenceResult> chain() const {
- if (continuation) {
- return ftl::Future(future).then(continuation).share();
- } else {
- return future;
- }
- }
- };
- std::vector<FenceAndContinuation> mPreviousReleaseFenceAndContinuations;
-
// Release fences for buffers that have not yet received a release
// callback. A release callback may not be given when capturing
// screenshots asynchronously. There may be no buffer update for the
diff --git a/services/surfaceflinger/LayerFE.cpp b/services/surfaceflinger/LayerFE.cpp
index b05f0ee..a346981 100644
--- a/services/surfaceflinger/LayerFE.cpp
+++ b/services/surfaceflinger/LayerFE.cpp
@@ -26,7 +26,6 @@
#include "LayerFE.h"
#include "SurfaceFlinger.h"
-#include "common/FlagManager.h"
#include "ui/FenceResult.h"
#include "ui/LayerStack.h"
@@ -84,8 +83,7 @@
// Ensures that no promise is left unfulfilled before the LayerFE is destroyed.
// An unfulfilled promise could occur when a screenshot is attempted, but the
// render area is invalid and there is no memory for the capture result.
- if (FlagManager::getInstance().ce_fence_promise() &&
- mReleaseFencePromiseStatus == ReleaseFencePromiseStatus::INITIALIZED) {
+ if (mReleaseFencePromiseStatus == ReleaseFencePromiseStatus::INITIALIZED) {
setReleaseFence(Fence::NO_FENCE);
}
}
@@ -176,6 +174,7 @@
layerSettings.edgeExtensionEffect = mSnapshot->edgeExtensionEffect;
// Record the name of the layer for debugging further down the stack.
layerSettings.name = mSnapshot->name;
+ layerSettings.luts = mSnapshot->luts;
if (hasEffect() && !hasBufferOrSidebandStream()) {
prepareEffectsClientComposition(layerSettings, targetSettings);
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 06c2f26..011fd9e 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -355,7 +355,7 @@
FenceResult fenceResult;
if (FlagManager::getInstance().single_hop_screenshot() &&
- FlagManager::getInstance().ce_fence_promise() && mFlinger.mRenderEngine->isThreaded()) {
+ mFlinger.mRenderEngine->isThreaded()) {
std::vector<sp<LayerFE>> layerFEs;
auto displayState = mFlinger.getSnapshotsFromMainThread(renderAreaBuilder,
getLayerSnapshotsFn, layerFEs);
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
index ab9014e..eca8df2 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
@@ -722,13 +722,17 @@
const bool inPrimaryPhysicalRange =
policy->primaryRanges.physical.includes(modePtr->getPeakFps());
const bool inPrimaryRenderRange = policy->primaryRanges.render.includes(fps);
- if (((policy->primaryRangeIsSingleRate() && !inPrimaryPhysicalRange) ||
+ if (!mIsVrrDevice.load() &&
+ ((policy->primaryRangeIsSingleRate() && !inPrimaryPhysicalRange) ||
!inPrimaryRenderRange) &&
!(layer.focused &&
(layer.vote == LayerVoteType::ExplicitDefault ||
layer.vote == LayerVoteType::ExplicitExact))) {
// Only focused layers with ExplicitDefault frame rate settings are allowed to score
// refresh rates outside the primary range.
+ ALOGV("%s ignores %s (primaryRangeIsSingleRate). Current mode = %s",
+ formatLayerInfo(layer, weight).c_str(), to_string(*modePtr).c_str(),
+ to_string(activeMode).c_str());
continue;
}
@@ -852,7 +856,8 @@
to_string(descending.front().frameRateMode.fps).c_str());
return {descending, kNoSignals};
} else {
- ALOGV("primaryRangeIsSingleRate");
+ ALOGV("%s (primaryRangeIsSingleRate)",
+ to_string(ranking.front().frameRateMode.fps).c_str());
SFTRACE_FORMAT_INSTANT("%s (primaryRangeIsSingleRate)",
to_string(ranking.front().frameRateMode.fps).c_str());
return {ranking, kNoSignals};
@@ -932,6 +937,8 @@
using LayerVoteType = RefreshRateSelector::LayerVoteType;
if (layer->vote == LayerVoteType::Max || layer->vote == LayerVoteType::Heuristic) {
+ ALOGV("%s: %s skips uid=%d due to the vote", __func__,
+ formatLayerInfo(*layer, layer->weight).c_str(), layer->ownerUid);
skipUid = true;
break;
}
@@ -1014,12 +1021,14 @@
// Layers with ExplicitExactOrMultiple expect touch boost
if (globalSignals.touch && hasExplicitExactOrMultiple) {
+ ALOGV("%s: Skipping for touch (input signal): uid=%d", __func__, uid);
continue;
}
// Mirrors getRankedFrameRates. If there is no ExplicitDefault, expect touch boost and
// skip frame rate override.
if (hasHighHint && !hasExplicitDefault) {
+ ALOGV("%s: Skipping for touch (HighHint): uid=%d", __func__, uid);
continue;
}
@@ -1043,6 +1052,9 @@
constexpr bool isSeamlessSwitch = true;
const auto layerScore = calculateLayerScoreLocked(*layer, fps, isSeamlessSwitch);
score += layer->weight * layerScore;
+ ALOGV("%s: %s gives %s fps score of %.4f", __func__,
+ formatLayerInfo(*layer, layer->weight).c_str(), to_string(fps).c_str(),
+ layerScore);
}
}
@@ -1297,6 +1309,8 @@
LOG_ALWAYS_FATAL_IF(!activeModeOpt);
mActiveModeOpt = FrameRateMode{activeModeOpt->get()->getPeakFps(),
ftl::as_non_null(activeModeOpt->get())};
+ mIsVrrDevice = FlagManager::getInstance().vrr_config() &&
+ activeModeOpt->get()->getVrrConfig().has_value();
const auto sortedModes = sortByRefreshRate(mDisplayModes);
mMinRefreshRateModeIt = sortedModes.front();
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index cad179c..d35a76a 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -83,6 +83,7 @@
#include <renderengine/RenderEngine.h>
#include <renderengine/impl/ExternalTexture.h>
#include <scheduler/FrameTargeter.h>
+#include <statslog_surfaceflinger.h>
#include <sys/types.h>
#include <ui/ColorSpace.h>
#include <ui/DebugUtils.h>
@@ -1655,19 +1656,22 @@
outProperties->combinations.emplace_back(outCombination);
}
outProperties->supportMixedColorSpaces = aidlProperties.supportMixedColorSpaces;
- if (aidlProperties.lutProperties.has_value()) {
+ if (aidlProperties.lutProperties) {
std::vector<gui::LutProperties> outLutProperties;
- for (const auto& properties : aidlProperties.lutProperties.value()) {
- gui::LutProperties currentProperties;
- currentProperties.dimension =
- static_cast<gui::LutProperties::Dimension>(properties->dimension);
- currentProperties.size = properties->size;
- currentProperties.samplingKeys.reserve(properties->samplingKeys.size());
- std::transform(properties->samplingKeys.cbegin(), properties->samplingKeys.cend(),
- std::back_inserter(currentProperties.samplingKeys), [](const auto& val) {
- return static_cast<gui::LutProperties::SamplingKey>(val);
- });
- outLutProperties.push_back(std::move(currentProperties));
+ for (auto properties : *aidlProperties.lutProperties) {
+ if (!properties) {
+ gui::LutProperties currentProperties;
+ currentProperties.dimension =
+ static_cast<gui::LutProperties::Dimension>(properties->dimension);
+ currentProperties.size = properties->size;
+ currentProperties.samplingKeys.reserve(properties->samplingKeys.size());
+ std::transform(properties->samplingKeys.cbegin(), properties->samplingKeys.cend(),
+ std::back_inserter(currentProperties.samplingKeys),
+ [](const auto& val) {
+ return static_cast<gui::LutProperties::SamplingKey>(val);
+ });
+ outLutProperties.push_back(std::move(currentProperties));
+ }
}
outProperties->lutProperties.emplace(outLutProperties.begin(), outLutProperties.end());
}
@@ -2758,16 +2762,6 @@
compositionengine::Feature::kSnapshotLayerMetadata);
refreshArgs.bufferIdsToUncache = std::move(mBufferIdsToUncache);
-
- if (!FlagManager::getInstance().ce_fence_promise()) {
- refreshArgs.layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size());
- for (auto& [layer, _] : mLayersWithQueuedFrames) {
- if (const auto& layerFE = layer->getCompositionEngineLayerFE(
- {static_cast<uint32_t>(layer->sequence)}))
- refreshArgs.layersWithQueuedFrames.push_back(layerFE);
- }
- }
-
refreshArgs.outputColorSetting = mDisplayColorSetting;
refreshArgs.forceOutputColorMode = mForceColorMode;
@@ -2831,51 +2825,35 @@
layer->onPreComposition(refreshArgs.refreshStartTime);
}
- if (FlagManager::getInstance().ce_fence_promise()) {
- for (auto& [layer, layerFE] : layers) {
- attachReleaseFenceFutureToLayer(layer, layerFE,
- layerFE->mSnapshot->outputFilter.layerStack);
- }
+ for (auto& [layer, layerFE] : layers) {
+ attachReleaseFenceFutureToLayer(layer, layerFE,
+ layerFE->mSnapshot->outputFilter.layerStack);
+ }
- refreshArgs.layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size());
- for (auto& [layer, _] : mLayersWithQueuedFrames) {
- if (const auto& layerFE = layer->getCompositionEngineLayerFE(
- {static_cast<uint32_t>(layer->sequence)})) {
- refreshArgs.layersWithQueuedFrames.push_back(layerFE);
- // Some layers are not displayed and do not yet have a future release fence
- if (layerFE->getReleaseFencePromiseStatus() ==
- LayerFE::ReleaseFencePromiseStatus::UNINITIALIZED ||
- layerFE->getReleaseFencePromiseStatus() ==
- LayerFE::ReleaseFencePromiseStatus::FULFILLED) {
- // layerStack is invalid because layer is not on a display
- attachReleaseFenceFutureToLayer(layer.get(), layerFE.get(),
- ui::INVALID_LAYER_STACK);
- }
+ refreshArgs.layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size());
+ for (auto& [layer, _] : mLayersWithQueuedFrames) {
+ if (const auto& layerFE =
+ layer->getCompositionEngineLayerFE({static_cast<uint32_t>(layer->sequence)})) {
+ refreshArgs.layersWithQueuedFrames.push_back(layerFE);
+ // Some layers are not displayed and do not yet have a future release fence
+ if (layerFE->getReleaseFencePromiseStatus() ==
+ LayerFE::ReleaseFencePromiseStatus::UNINITIALIZED ||
+ layerFE->getReleaseFencePromiseStatus() ==
+ LayerFE::ReleaseFencePromiseStatus::FULFILLED) {
+ // layerStack is invalid because layer is not on a display
+ attachReleaseFenceFutureToLayer(layer.get(), layerFE.get(),
+ ui::INVALID_LAYER_STACK);
}
}
+ }
- mCompositionEngine->present(refreshArgs);
- moveSnapshotsFromCompositionArgs(refreshArgs, layers);
+ mCompositionEngine->present(refreshArgs);
+ moveSnapshotsFromCompositionArgs(refreshArgs, layers);
- for (auto& [layer, layerFE] : layers) {
- CompositionResult compositionResult{layerFE->stealCompositionResult()};
- if (compositionResult.lastClientCompositionFence) {
- layer->setWasClientComposed(compositionResult.lastClientCompositionFence);
- }
- }
-
- } else {
- mCompositionEngine->present(refreshArgs);
- moveSnapshotsFromCompositionArgs(refreshArgs, layers);
-
- for (auto [layer, layerFE] : layers) {
- CompositionResult compositionResult{layerFE->stealCompositionResult()};
- for (auto& [releaseFence, layerStack] : compositionResult.releaseFences) {
- layer->onLayerDisplayed(std::move(releaseFence), layerStack);
- }
- if (compositionResult.lastClientCompositionFence) {
- layer->setWasClientComposed(compositionResult.lastClientCompositionFence);
- }
+ for (auto& [layer, layerFE] : layers) {
+ CompositionResult compositionResult{layerFE->stealCompositionResult()};
+ if (compositionResult.lastClientCompositionFence) {
+ layer->setWasClientComposed(compositionResult.lastClientCompositionFence);
}
}
@@ -3130,13 +3108,8 @@
auto optDisplay = layerStackToDisplay.get(layerStack);
if (optDisplay && !optDisplay->get()->isVirtual()) {
auto fence = getHwComposer().getPresentFence(optDisplay->get()->getPhysicalId());
- if (FlagManager::getInstance().ce_fence_promise()) {
- layer->prepareReleaseCallbacks(ftl::yield<FenceResult>(fence),
- ui::INVALID_LAYER_STACK);
- } else {
- layer->onLayerDisplayed(ftl::yield<FenceResult>(fence).share(),
- ui::INVALID_LAYER_STACK);
- }
+ layer->prepareReleaseCallbacks(ftl::yield<FenceResult>(fence),
+ ui::INVALID_LAYER_STACK);
}
}
layer->releasePendingBuffer(presentTime.ns());
@@ -3174,6 +3147,19 @@
mAddingHDRLayerInfoListener = false;
}
+ for (const auto& layerEvent : mLayerEvents) {
+ auto result =
+ stats::stats_write(stats::SURFACE_CONTROL_EVENT,
+ static_cast<int32_t>(layerEvent.uid),
+ static_cast<int64_t>(layerEvent.timeSinceLastEvent.count()),
+ static_cast<int32_t>(layerEvent.dataspace));
+ if (result < 0) {
+ ALOGW("Failed to report layer event with error: %d", result);
+ }
+ }
+
+ mLayerEvents.clear();
+
if (haveNewListeners || mHdrLayerInfoChanged) {
for (auto& [compositionDisplay, listener] : hdrInfoListeners) {
HdrLayerInfoReporter::HdrLayerInfo info;
@@ -7219,8 +7205,7 @@
return;
}
- if (FlagManager::getInstance().single_hop_screenshot() &&
- FlagManager::getInstance().ce_fence_promise() && mRenderEngine->isThreaded()) {
+ if (FlagManager::getInstance().single_hop_screenshot() && mRenderEngine->isThreaded()) {
std::vector<sp<LayerFE>> layerFEs;
auto displayState =
getSnapshotsFromMainThread(renderAreaBuilder, getLayerSnapshotsFn, layerFEs);
@@ -7461,10 +7446,8 @@
auto takeScreenshotFn = [=, this, renderAreaBuilder = std::move(renderAreaBuilder)]() REQUIRES(
kMainThreadContext) mutable -> ftl::SharedFuture<FenceResult> {
auto layers = getLayerSnapshotsFn();
- if (FlagManager::getInstance().ce_fence_promise()) {
- for (auto& [layer, layerFE] : layers) {
- attachReleaseFenceFutureToLayer(layer, layerFE.get(), ui::INVALID_LAYER_STACK);
- }
+ for (auto& [layer, layerFE] : layers) {
+ attachReleaseFenceFutureToLayer(layer, layerFE.get(), ui::INVALID_LAYER_STACK);
}
auto displayState = getDisplayStateFromRenderAreaBuilder(renderAreaBuilder);
@@ -7661,36 +7644,13 @@
// TODO(b/196334700) Once we use RenderEngineThreaded everywhere we can always defer the call
// to CompositionEngine::present.
ftl::SharedFuture<FenceResult> presentFuture;
- if (FlagManager::getInstance().single_hop_screenshot() &&
- FlagManager::getInstance().ce_fence_promise() && mRenderEngine->isThreaded()) {
+ if (FlagManager::getInstance().single_hop_screenshot() && mRenderEngine->isThreaded()) {
presentFuture = ftl::yield(present()).share();
} else {
presentFuture = mRenderEngine->isThreaded() ? ftl::defer(std::move(present)).share()
: ftl::yield(present()).share();
}
- if (!FlagManager::getInstance().ce_fence_promise()) {
- for (auto& [layer, layerFE] : layers) {
- layer->onLayerDisplayed(presentFuture, ui::INVALID_LAYER_STACK,
- [layerFE = std::move(layerFE)](FenceResult) {
- if (FlagManager::getInstance()
- .screenshot_fence_preservation()) {
- const auto compositionResult =
- layerFE->stealCompositionResult();
- const auto& fences = compositionResult.releaseFences;
- // CompositionEngine may choose to cull layers that
- // aren't visible, so pass a non-fence.
- return fences.empty() ? Fence::NO_FENCE
- : fences.back().first.get();
- } else {
- return layerFE->stealCompositionResult()
- .releaseFences.back()
- .first.get();
- }
- });
- }
- }
-
return presentFuture;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index db0e15e..31218ed 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -1221,6 +1221,14 @@
bool mHdrLayerInfoChanged = false;
+ struct LayerEvent {
+ uid_t uid;
+ int32_t layerId;
+ ui::Dataspace dataspace;
+ std::chrono::milliseconds timeSinceLastEvent;
+ };
+ std::vector<LayerEvent> mLayerEvents;
+
// Used to ensure we omit a callback when HDR layer info listener is newly added but the
// scene hasn't changed
bool mAddingHDRLayerInfoListener = false;
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp
index c6856ae..de4825b 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.cpp
+++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp
@@ -28,7 +28,6 @@
#include "Utils/FenceUtils.h"
#include <binder/IInterface.h>
-#include <common/FlagManager.h>
#include <common/trace.h>
#include <utils/RefBase.h>
@@ -127,14 +126,8 @@
if (surfaceControl) {
sp<Fence> prevFence = nullptr;
- if (FlagManager::getInstance().ce_fence_promise()) {
- for (auto& future : handle->previousReleaseFences) {
- mergeFence(handle->name.c_str(), future.get().value_or(Fence::NO_FENCE), prevFence);
- }
- } else {
- for (const auto& future : handle->previousSharedReleaseFences) {
- mergeFence(handle->name.c_str(), future.get().value_or(Fence::NO_FENCE), prevFence);
- }
+ for (auto& future : handle->previousReleaseFences) {
+ mergeFence(handle->name.c_str(), future.get().value_or(Fence::NO_FENCE), prevFence);
}
handle->previousReleaseFence = prevFence;
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h
index 14a7487..d81d8d0 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.h
+++ b/services/surfaceflinger/TransactionCallbackInvoker.h
@@ -43,7 +43,6 @@
std::string name;
sp<Fence> previousReleaseFence;
std::vector<ftl::Future<FenceResult>> previousReleaseFences;
- std::vector<ftl::SharedFuture<FenceResult>> previousSharedReleaseFences;
std::variant<nsecs_t, sp<Fence>> acquireTimeOrFence = -1;
nsecs_t latchTime = -1;
std::optional<uint32_t> transformHint = std::nullopt;
diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp
index 12d6138..658bca6 100644
--- a/services/surfaceflinger/common/FlagManager.cpp
+++ b/services/surfaceflinger/common/FlagManager.cpp
@@ -116,6 +116,7 @@
DUMP_SERVER_FLAG(adpf_use_fmq_channel);
/// Trunk stable readonly flags ///
+ DUMP_READ_ONLY_FLAG(adpf_fmq_sf);
DUMP_READ_ONLY_FLAG(connected_display);
DUMP_READ_ONLY_FLAG(enable_small_area_detection);
DUMP_READ_ONLY_FLAG(frame_rate_category_mrr);
@@ -132,7 +133,6 @@
DUMP_READ_ONLY_FLAG(fp16_client_target);
DUMP_READ_ONLY_FLAG(game_default_frame_rate);
DUMP_READ_ONLY_FLAG(enable_layer_command_batching);
- DUMP_READ_ONLY_FLAG(screenshot_fence_preservation);
DUMP_READ_ONLY_FLAG(vulkan_renderengine);
DUMP_READ_ONLY_FLAG(renderable_buffer_usage);
DUMP_READ_ONLY_FLAG(vrr_bugfix_24q4);
@@ -140,7 +140,6 @@
DUMP_READ_ONLY_FLAG(restore_blur_step);
DUMP_READ_ONLY_FLAG(dont_skip_on_early_ro);
DUMP_READ_ONLY_FLAG(protected_if_client);
- DUMP_READ_ONLY_FLAG(ce_fence_promise);
DUMP_READ_ONLY_FLAG(idle_screen_refresh_rate_timeout);
DUMP_READ_ONLY_FLAG(graphite_renderengine);
DUMP_READ_ONLY_FLAG(filter_frames_before_trace_starts);
@@ -157,6 +156,7 @@
DUMP_READ_ONLY_FLAG(single_hop_screenshot);
DUMP_READ_ONLY_FLAG(trace_frame_rate_override);
DUMP_READ_ONLY_FLAG(true_hdr_screenshots);
+ DUMP_READ_ONLY_FLAG(display_config_error_hal);
#undef DUMP_READ_ONLY_FLAG
#undef DUMP_SERVER_FLAG
@@ -222,6 +222,7 @@
"SkiaTracingFeature__use_skia_tracing")
/// Trunk stable readonly flags ///
+FLAG_MANAGER_READ_ONLY_FLAG(adpf_fmq_sf, "")
FLAG_MANAGER_READ_ONLY_FLAG(connected_display, "")
FLAG_MANAGER_READ_ONLY_FLAG(enable_small_area_detection, "")
FLAG_MANAGER_READ_ONLY_FLAG(frame_rate_category_mrr, "debug.sf.frame_rate_category_mrr")
@@ -239,7 +240,6 @@
FLAG_MANAGER_READ_ONLY_FLAG(fp16_client_target, "debug.sf.fp16_client_target")
FLAG_MANAGER_READ_ONLY_FLAG(game_default_frame_rate, "")
FLAG_MANAGER_READ_ONLY_FLAG(enable_layer_command_batching, "debug.sf.enable_layer_command_batching")
-FLAG_MANAGER_READ_ONLY_FLAG(screenshot_fence_preservation, "debug.sf.screenshot_fence_preservation")
FLAG_MANAGER_READ_ONLY_FLAG(vulkan_renderengine, "debug.renderengine.vulkan")
FLAG_MANAGER_READ_ONLY_FLAG(renderable_buffer_usage, "")
FLAG_MANAGER_READ_ONLY_FLAG(restore_blur_step, "debug.renderengine.restore_blur_step")
@@ -247,7 +247,6 @@
FLAG_MANAGER_READ_ONLY_FLAG(protected_if_client, "")
FLAG_MANAGER_READ_ONLY_FLAG(vrr_bugfix_24q4, "");
FLAG_MANAGER_READ_ONLY_FLAG(vrr_bugfix_dropped_frame, "")
-FLAG_MANAGER_READ_ONLY_FLAG(ce_fence_promise, "");
FLAG_MANAGER_READ_ONLY_FLAG(graphite_renderengine, "debug.renderengine.graphite")
FLAG_MANAGER_READ_ONLY_FLAG(filter_frames_before_trace_starts, "")
FLAG_MANAGER_READ_ONLY_FLAG(latch_unsignaled_with_auto_refresh_changed, "");
@@ -262,6 +261,7 @@
FLAG_MANAGER_READ_ONLY_FLAG(force_compile_graphite_renderengine, "");
FLAG_MANAGER_READ_ONLY_FLAG(single_hop_screenshot, "");
FLAG_MANAGER_READ_ONLY_FLAG(true_hdr_screenshots, "debug.sf.true_hdr_screenshots");
+FLAG_MANAGER_READ_ONLY_FLAG(display_config_error_hal, "");
/// Trunk stable server flags ///
FLAG_MANAGER_SERVER_FLAG(refresh_rate_overlay_on_external_display, "")
diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h
index a1be194..4f34718 100644
--- a/services/surfaceflinger/common/include/common/FlagManager.h
+++ b/services/surfaceflinger/common/include/common/FlagManager.h
@@ -54,6 +54,7 @@
bool adpf_use_fmq_channel_fixed() const;
/// Trunk stable readonly flags ///
+ bool adpf_fmq_sf() const;
bool connected_display() const;
bool frame_rate_category_mrr() const;
bool enable_small_area_detection() const;
@@ -70,7 +71,6 @@
bool fp16_client_target() const;
bool game_default_frame_rate() const;
bool enable_layer_command_batching() const;
- bool screenshot_fence_preservation() const;
bool vulkan_renderengine() const;
bool vrr_bugfix_24q4() const;
bool vrr_bugfix_dropped_frame() const;
@@ -78,7 +78,6 @@
bool restore_blur_step() const;
bool dont_skip_on_early_ro() const;
bool protected_if_client() const;
- bool ce_fence_promise() const;
bool idle_screen_refresh_rate_timeout() const;
bool graphite_renderengine() const;
bool filter_frames_before_trace_starts() const;
@@ -95,6 +94,7 @@
bool single_hop_screenshot() const;
bool trace_frame_rate_override() const;
bool true_hdr_screenshots() const;
+ bool display_config_error_hal() const;
protected:
// overridden for unit tests
diff --git a/services/surfaceflinger/fuzzer/Android.bp b/services/surfaceflinger/fuzzer/Android.bp
index ae502cf..3582d38 100644
--- a/services/surfaceflinger/fuzzer/Android.bp
+++ b/services/surfaceflinger/fuzzer/Android.bp
@@ -32,12 +32,15 @@
"libsurfaceflinger_common",
],
srcs: [
+ ":libsurfaceflinger_backend_mock_sources",
+ ":libsurfaceflinger_mock_sources",
":libsurfaceflinger_sources",
],
defaults: [
"libsurfaceflinger_defaults",
],
header_libs: [
+ "libsurfaceflinger_backend_mock_headers",
"libsurfaceflinger_headers",
],
cflags: [
diff --git a/services/surfaceflinger/surfaceflinger_flags_new.aconfig b/services/surfaceflinger/surfaceflinger_flags_new.aconfig
index e40be51..f758879 100644
--- a/services/surfaceflinger/surfaceflinger_flags_new.aconfig
+++ b/services/surfaceflinger/surfaceflinger_flags_new.aconfig
@@ -4,6 +4,14 @@
container: "system"
flag {
+ name: "adpf_fmq_sf"
+ namespace: "game"
+ description: "Guards use of the ADPF FMQ system specifically for SurfaceFlinger"
+ bug: "315894228"
+ is_fixed_read_only: true
+} # adpf_fmq_sf
+
+flag {
name: "adpf_gpu_sf"
namespace: "game"
description: "Guards use of the sending ADPF GPU duration hint and load hints from SurfaceFlinger to Power HAL"
@@ -74,6 +82,14 @@
} # detached_mirror
flag {
+ name: "display_config_error_hal"
+ namespace: "core_graphics"
+ description: "Report HAL display configuration errors like modeset failure or link training failure"
+ bug: "374184110"
+ is_fixed_read_only: true
+} # display_config_error_hal
+
+flag {
name: "filter_frames_before_trace_starts"
namespace: "core_graphics"
description: "Do not trace FrameTimeline events for frames started before the trace started"
diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h
index 67a5247..bf5957a 100644
--- a/services/surfaceflinger/tests/TransactionTestHarnesses.h
+++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h
@@ -17,7 +17,6 @@
#define ANDROID_TRANSACTION_TEST_HARNESSES
#include <com_android_graphics_libgui_flags.h>
-#include <common/FlagManager.h>
#include <ui/DisplayState.h>
#include "LayerTransactionTest.h"
@@ -96,12 +95,8 @@
#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
t.setDisplayProjection(vDisplay, displayState.orientation,
Rect(displayState.layerStackSpaceRect), Rect(resolution));
- if (FlagManager::getInstance().ce_fence_promise()) {
- t.setDisplayLayerStack(vDisplay, layerStack);
- t.setLayerStack(mirrorSc, layerStack);
- } else {
- t.setDisplayLayerStack(vDisplay, ui::DEFAULT_LAYER_STACK);
- }
+ t.setDisplayLayerStack(vDisplay, layerStack);
+ t.setLayerStack(mirrorSc, layerStack);
t.apply();
SurfaceComposerClient::Transaction().apply(true);
@@ -121,10 +116,8 @@
// CompositionEngine::present may attempt to be called on the same
// display multiple times. The layerStack is set to invalid here so
// that the display is ignored if that scenario occurs.
- if (FlagManager::getInstance().ce_fence_promise()) {
- t.setLayerStack(mirrorSc, ui::INVALID_LAYER_STACK);
- t.apply(true);
- }
+ t.setLayerStack(mirrorSc, ui::INVALID_LAYER_STACK);
+ t.apply(true);
SurfaceComposerClient::destroyVirtualDisplay(vDisplay);
return sc;
}
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index f1bd87c..8269fcb 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -22,15 +22,40 @@
default_team: "trendy_team_android_core_graphics_stack",
}
+// This is a step towards pulling out the "backend" sources to clean up the
+// dependency graph between CompositionEngine and SurfaceFlinger.
+// MockNativeWindow doesn't strictly belong here, but this works for now so
+// that CompositionEngine tests can use these mocks.
filegroup {
- name: "libsurfaceflinger_mock_sources",
+ name: "libsurfaceflinger_backend_mock_sources",
srcs: [
- "mock/DisplayHardware/MockPowerHalController.cpp",
"mock/DisplayHardware/MockComposer.cpp",
"mock/DisplayHardware/MockHWC2.cpp",
+ "mock/DisplayHardware/MockHWComposer.cpp",
"mock/DisplayHardware/MockIPower.cpp",
"mock/DisplayHardware/MockPowerHintSessionWrapper.cpp",
"mock/DisplayHardware/MockPowerAdvisor.cpp",
+ "mock/DisplayHardware/MockPowerHalController.cpp",
+ "mock/system/window/MockNativeWindow.cpp",
+ ],
+}
+
+cc_library_headers {
+ name: "libsurfaceflinger_backend_mock_headers",
+ export_include_dirs: ["."],
+ static_libs: [
+ "libgmock",
+ "libgtest",
+ ],
+ export_static_lib_headers: [
+ "libgmock",
+ "libgtest",
+ ],
+}
+
+filegroup {
+ name: "libsurfaceflinger_mock_sources",
+ srcs: [
"mock/MockEventThread.cpp",
"mock/MockFrameTimeline.cpp",
"mock/MockFrameTracer.cpp",
@@ -39,7 +64,6 @@
"mock/MockVsyncController.cpp",
"mock/MockVSyncDispatch.cpp",
"mock/MockVSyncTracker.cpp",
- "mock/system/window/MockNativeWindow.cpp",
],
}
@@ -60,6 +84,7 @@
static_libs: ["libc++fs"],
header_libs: ["surfaceflinger_tests_common_headers"],
srcs: [
+ ":libsurfaceflinger_backend_mock_sources",
":libsurfaceflinger_mock_sources",
":libsurfaceflinger_sources",
"libsurfaceflinger_unittest_main.cpp",
@@ -199,6 +224,7 @@
"libpowermanager",
"libprocessgroup",
"libprotobuf-cpp-lite",
+ "libstatslog_surfaceflinger",
"libSurfaceFlingerProp",
"libsync",
"libui",
diff --git a/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp
index c879280..8375bb9 100644
--- a/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp
@@ -85,6 +85,7 @@
int64_t mSessionId = 123;
SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel, true);
SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel_fixed, false);
+ SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::adpf_fmq_sf, false);
};
bool PowerAdvisorTest::sessionExists() {
@@ -184,6 +185,7 @@
SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::adpf_gpu_sf,
config.adpfGpuFlagOn);
SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel_fixed, config.usesFmq);
+ SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::adpf_fmq_sf, config.usesFmq);
mPowerAdvisor->onBootFinished();
bool expectsFmqSuccess = config.usesSharedFmqFlag && !config.fmqFull;
if (config.usesFmq) {
@@ -789,6 +791,7 @@
TEST_F(PowerAdvisorTest, fmq_sendHint) {
SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel_fixed, true);
+ SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::adpf_fmq_sf, true);
mPowerAdvisor->onBootFinished();
SetUpFmq(true, false);
auto startTime = uptimeNanos();
@@ -807,6 +810,7 @@
TEST_F(PowerAdvisorTest, fmq_sendHint_noSharedFlag) {
SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel_fixed, true);
+ SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::adpf_fmq_sf, true);
mPowerAdvisor->onBootFinished();
SetUpFmq(false, false);
SessionHint hint;
@@ -821,6 +825,7 @@
TEST_F(PowerAdvisorTest, fmq_sendHint_queueFull) {
SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel_fixed, true);
+ SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::adpf_fmq_sf, true);
mPowerAdvisor->onBootFinished();
SetUpFmq(true, true);
ASSERT_EQ(mBackendFmq->availableToRead(), 2uL);
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
index adbd868..29e1c21 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
@@ -308,6 +308,42 @@
<< " category=" << ftl::enum_string(testCase.frameRateCategory);
}
}
+
+ template <class T>
+ std::vector<LayerRequirement> createLayers(const std::initializer_list<T>& surfaceVotes) {
+ std::vector<LayerRequirement> layers;
+ for (auto surfaceVote : surfaceVotes) {
+ ALOGI("**** %s: Adding layers for %s: (desiredFrameRate=%s, voteType=%s), "
+ "(frameRateCategory=%s)",
+ __func__, surfaceVote.name.c_str(),
+ to_string(surfaceVote.desiredFrameRate).c_str(),
+ ftl::enum_string(surfaceVote.voteType).c_str(),
+ ftl::enum_string(surfaceVote.frameRateCategory).c_str());
+
+ if (surfaceVote.desiredFrameRate.isValid()) {
+ std::stringstream ss;
+ ss << surfaceVote.name << " (" << surfaceVote.weight << "): ExplicitDefault ("
+ << to_string(surfaceVote.desiredFrameRate) << ")";
+ LayerRequirement layer = {.name = ss.str(),
+ .vote = surfaceVote.voteType,
+ .desiredRefreshRate = surfaceVote.desiredFrameRate,
+ .weight = surfaceVote.weight};
+ layers.push_back(layer);
+ }
+
+ if (surfaceVote.frameRateCategory != FrameRateCategory::Default) {
+ std::stringstream ss;
+ ss << surfaceVote.name << " (" << surfaceVote.weight << "): ExplicitCategory ("
+ << ftl::enum_string(surfaceVote.frameRateCategory) << ")";
+ LayerRequirement layer = {.name = ss.str(),
+ .vote = LayerVoteType::ExplicitCategory,
+ .frameRateCategory = surfaceVote.frameRateCategory,
+ .weight = surfaceVote.weight};
+ layers.push_back(layer);
+ }
+ }
+ return layers;
+ }
};
RefreshRateSelectorTest::RefreshRateSelectorTest() {
@@ -1776,6 +1812,98 @@
selector);
}
+TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_multiSurface_arr) {
+ if (GetParam() != Config::FrameRateOverride::Enabled) {
+ return;
+ }
+
+ SET_FLAG_FOR_TEST(flags::vrr_config, true);
+
+ auto selector = createSelector(kVrrMode_120, kModeId120);
+
+ // Switch the policy to be more like an ARR device (primary range is a single rate).
+ constexpr FpsRange k120_120Hz = {120_Hz, 120_Hz};
+ constexpr FpsRange k0_120Hz = {0_Hz, 120_Hz};
+ constexpr FpsRanges kPrimaryRanges = {/*physical*/ k120_120Hz,
+ /*render*/ k120_120Hz};
+ constexpr FpsRanges kAppRequestRanges = {/*physical*/ k120_120Hz,
+ /*render*/ k0_120Hz};
+ EXPECT_EQ(SetPolicyResult::Changed,
+ selector.setDisplayManagerPolicy(
+ {/*defaultMode*/ kModeId120, kPrimaryRanges, kAppRequestRanges}));
+
+ // Surface can translate to multiple layers in SF scheduler due to category and frame rate
+ // value.
+ struct SurfaceVote {
+ // Params
+ std::string name = "";
+ Fps desiredFrameRate = 0_Hz;
+ LayerVoteType voteType = LayerVoteType::ExplicitDefault;
+ FrameRateCategory frameRateCategory = FrameRateCategory::Default;
+ float weight = 1.f;
+ };
+
+ auto layers = createLayers(
+ std::initializer_list<SurfaceVote>{{.name = "60 fixed source",
+ .desiredFrameRate = 60_Hz,
+ .voteType = LayerVoteType::ExplicitExactOrMultiple,
+ .weight = 0.27f},
+ {.name = "1 fixed source + NoPreference",
+ .desiredFrameRate = 1_Hz,
+ .voteType = LayerVoteType::ExplicitExactOrMultiple,
+ .frameRateCategory =
+ FrameRateCategory::NoPreference}});
+ auto actualRankedFrameRates = selector.getRankedFrameRates(layers);
+ EXPECT_EQ(60_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps);
+
+ layers = createLayers(
+ std::initializer_list<SurfaceVote>{{.name = "60 fixed source",
+ .desiredFrameRate = 60_Hz,
+ .voteType = LayerVoteType::ExplicitExactOrMultiple,
+ .weight = 0.27f},
+ {.name = "1 fixed source + Normal",
+ .desiredFrameRate = 1_Hz,
+ .voteType = LayerVoteType::ExplicitExactOrMultiple,
+ .frameRateCategory = FrameRateCategory::Normal}});
+ actualRankedFrameRates = selector.getRankedFrameRates(layers);
+ EXPECT_EQ(60_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps);
+
+ layers = createLayers(std::initializer_list<SurfaceVote>{
+ {.name = "30 fixed source + NoPreference",
+ .desiredFrameRate = 30_Hz,
+ .voteType = LayerVoteType::ExplicitExactOrMultiple,
+ .frameRateCategory = FrameRateCategory::NoPreference}});
+ actualRankedFrameRates = selector.getRankedFrameRates(layers);
+ EXPECT_EQ(30_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps);
+
+ layers = createLayers(std::initializer_list<SurfaceVote>{
+ {.name = "1 fixed source + NoPreference",
+ .desiredFrameRate = 1_Hz,
+ .voteType = LayerVoteType::ExplicitExactOrMultiple,
+ .frameRateCategory = FrameRateCategory::NoPreference}});
+ actualRankedFrameRates = selector.getRankedFrameRates(layers);
+ // Result affected by RefreshRateSelector.kMinSupportedFrameRate.
+ EXPECT_EQ(20_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps);
+
+ layers = createLayers(std::initializer_list<SurfaceVote>{
+ {.name = "24 fixed source + NoPreference",
+ .desiredFrameRate = 24_Hz,
+ .voteType = LayerVoteType::ExplicitExactOrMultiple,
+ .frameRateCategory = FrameRateCategory::NoPreference}});
+ actualRankedFrameRates = selector.getRankedFrameRates(layers);
+ EXPECT_EQ(24_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps);
+
+ layers = createLayers(std::initializer_list<SurfaceVote>{
+ {.name = "23.976 fixed source + NoPreference",
+ .desiredFrameRate = 23.976_Hz,
+ .voteType = LayerVoteType::ExplicitExactOrMultiple,
+ .frameRateCategory = FrameRateCategory::NoPreference}});
+ actualRankedFrameRates = selector.getRankedFrameRates(layers);
+ // Chooses 120 unless certain threshold is set, see tests test23976Chooses120 and
+ // test23976Chooses60IfThresholdIs120.
+ EXPECT_EQ(120_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps);
+}
+
TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_60_120) {
auto selector = createSelector(makeModes(kMode60, kMode120), kModeId60);
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 615cc94..3e6a768 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -185,7 +185,7 @@
(Display, std::vector<Layer>*,
std::vector<aidl::android::hardware::graphics::composer3::DisplayLuts::LayerLut>*));
MOCK_METHOD(Error, setLayerLuts,
- (Display, Layer, std::vector<aidl::android::hardware::graphics::composer3::Lut>&));
+ (Display, Layer, aidl::android::hardware::graphics::composer3::Luts&));
};
} // namespace Hwc2::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
index 53ed2e1..121104d 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
@@ -126,6 +126,8 @@
(uint32_t, const android::sp<android::GraphicBuffer> &,
const android::sp<android::Fence> &),
(override));
+ MOCK_METHOD(hal::Error, setBufferSlotsToClear,
+ (const std::vector<uint32_t>& slotsToClear, uint32_t activeBufferSlot), (override));
MOCK_METHOD(hal::Error, setSurfaceDamage, (const android::Region &), (override));
MOCK_METHOD(hal::Error, setBlendMode, (hal::BlendMode), (override));
MOCK_METHOD(hal::Error, setColor, (aidl::android::hardware::graphics::composer3::Color),
@@ -147,8 +149,8 @@
(const std::string &, bool, const std::vector<uint8_t> &), (override));
MOCK_METHOD(hal::Error, setBrightness, (float), (override));
MOCK_METHOD(hal::Error, setBlockingRegion, (const android::Region &), (override));
- MOCK_METHOD(hal::Error, setLuts,
- (std::vector<aidl::android::hardware::graphics::composer3::Lut>&), (override));
+ MOCK_METHOD(hal::Error, setLuts, (aidl::android::hardware::graphics::composer3::Luts&),
+ (override));
};
} // namespace android::HWC2::mock
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.cpp b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWComposer.cpp
similarity index 81%
rename from services/surfaceflinger/CompositionEngine/tests/MockHWComposer.cpp
rename to services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWComposer.cpp
index ae52670..f310633 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWComposer.cpp
@@ -16,17 +16,11 @@
#include "MockHWComposer.h"
-namespace android {
-
-// This will go away once HWComposer is moved into the "backend" library
-HWComposer::~HWComposer() = default;
-
-namespace mock {
+namespace android::mock {
// The Google Mock documentation recommends explicit non-header instantiations
// for better compile time performance.
HWComposer::HWComposer() = default;
HWComposer::~HWComposer() = default;
-} // namespace mock
-} // namespace android
+} // namespace android::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWComposer.h
new file mode 100644
index 0000000..fa7128c
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWComposer.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2024 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 <gmock/gmock.h>
+
+#include "DisplayHardware/HWComposer.h"
+
+namespace android::mock {
+
+class HWComposer : public android::HWComposer {
+public:
+ using HWDisplayId = android::hardware::graphics::composer::hal::HWDisplayId;
+ using PowerMode = android::hardware::graphics::composer::hal::PowerMode;
+
+ HWComposer();
+ ~HWComposer() override;
+
+ MOCK_METHOD(void, setCallback, (HWC2::ComposerCallback&), (override));
+ MOCK_METHOD(bool, getDisplayIdentificationData,
+ (HWDisplayId, uint8_t*, DisplayIdentificationData*), (const, override));
+ MOCK_METHOD(bool, hasCapability, (aidl::android::hardware::graphics::composer3::Capability),
+ (const, override));
+ MOCK_METHOD(bool, hasDisplayCapability,
+ (HalDisplayId, aidl::android::hardware::graphics::composer3::DisplayCapability),
+ (const, override));
+
+ MOCK_METHOD(size_t, getMaxVirtualDisplayCount, (), (const, override));
+ MOCK_METHOD(size_t, getMaxVirtualDisplayDimension, (), (const, override));
+ MOCK_METHOD(bool, allocateVirtualDisplay, (HalVirtualDisplayId, ui::Size, ui::PixelFormat*),
+ (override));
+ MOCK_METHOD(void, allocatePhysicalDisplay,
+ (hal::HWDisplayId, PhysicalDisplayId, std::optional<ui::Size>), (override));
+
+ MOCK_METHOD(std::shared_ptr<HWC2::Layer>, createLayer, (HalDisplayId), (override));
+ MOCK_METHOD(status_t, getDeviceCompositionChanges,
+ (HalDisplayId, bool, std::optional<std::chrono::steady_clock::time_point>, nsecs_t,
+ Fps, std::optional<android::HWComposer::DeviceRequestedChanges>*));
+ MOCK_METHOD(status_t, setClientTarget,
+ (HalDisplayId, uint32_t, const sp<Fence>&, const sp<GraphicBuffer>&, ui::Dataspace,
+ float),
+ (override));
+ MOCK_METHOD(status_t, presentAndGetReleaseFences,
+ (HalDisplayId, std::optional<std::chrono::steady_clock::time_point>), (override));
+ MOCK_METHOD(status_t, executeCommands, (HalDisplayId));
+ MOCK_METHOD(status_t, setPowerMode, (PhysicalDisplayId, PowerMode), (override));
+ MOCK_METHOD(status_t, setColorTransform, (HalDisplayId, const mat4&), (override));
+ MOCK_METHOD(void, disconnectDisplay, (HalDisplayId), (override));
+ MOCK_METHOD(sp<Fence>, getPresentFence, (HalDisplayId), (const, override));
+ MOCK_METHOD(nsecs_t, getPresentTimestamp, (PhysicalDisplayId), (const, override));
+ MOCK_METHOD(sp<Fence>, getLayerReleaseFence, (HalDisplayId, HWC2::Layer*), (const, override));
+ MOCK_METHOD(status_t, setOutputBuffer,
+ (HalVirtualDisplayId, const sp<Fence>&, const sp<GraphicBuffer>&), (override));
+ MOCK_METHOD(void, clearReleaseFences, (HalDisplayId), (override));
+ MOCK_METHOD(status_t, getHdrCapabilities, (HalDisplayId, HdrCapabilities*), (override));
+ MOCK_METHOD(int32_t, getSupportedPerFrameMetadata, (HalDisplayId), (const, override));
+ MOCK_METHOD(std::vector<ui::RenderIntent>, getRenderIntents, (HalDisplayId, ui::ColorMode),
+ (const, override));
+ MOCK_METHOD(mat4, getDataspaceSaturationMatrix, (HalDisplayId, ui::Dataspace), (override));
+ MOCK_METHOD(status_t, getDisplayedContentSamplingAttributes,
+ (HalDisplayId, ui::PixelFormat*, ui::Dataspace*, uint8_t*), (override));
+ MOCK_METHOD(status_t, setDisplayContentSamplingEnabled, (HalDisplayId, bool, uint8_t, uint64_t),
+ (override));
+ MOCK_METHOD(status_t, getDisplayedContentSample,
+ (HalDisplayId, uint64_t, uint64_t, DisplayedFrameStats*), (override));
+ MOCK_METHOD(ftl::Future<status_t>, setDisplayBrightness,
+ (PhysicalDisplayId, float, float, const Hwc2::Composer::DisplayBrightnessOptions&),
+ (override));
+ MOCK_METHOD(std::optional<DisplayIdentificationInfo>, onHotplug,
+ (hal::HWDisplayId, hal::Connection), (override));
+ MOCK_METHOD(bool, updatesDeviceProductInfoOnHotplugReconnect, (), (const, override));
+ MOCK_METHOD(std::optional<PhysicalDisplayId>, onVsync, (hal::HWDisplayId, int64_t));
+ MOCK_METHOD(void, setVsyncEnabled, (PhysicalDisplayId, hal::Vsync), (override));
+ MOCK_METHOD(bool, isConnected, (PhysicalDisplayId), (const, override));
+ MOCK_METHOD(std::vector<HWComposer::HWCDisplayMode>, getModes, (PhysicalDisplayId, int32_t),
+ (const, override));
+ MOCK_METHOD((ftl::Expected<hal::HWConfigId, status_t>), getActiveMode, (PhysicalDisplayId),
+ (const, override));
+ MOCK_METHOD(std::vector<ui::ColorMode>, getColorModes, (PhysicalDisplayId), (const, override));
+ MOCK_METHOD(status_t, setActiveColorMode, (PhysicalDisplayId, ui::ColorMode, ui::RenderIntent),
+ (override));
+ MOCK_METHOD(ui::DisplayConnectionType, getDisplayConnectionType, (PhysicalDisplayId),
+ (const, override));
+ MOCK_METHOD(bool, isVsyncPeriodSwitchSupported, (PhysicalDisplayId), (const, override));
+ MOCK_METHOD((ftl::Expected<nsecs_t, status_t>), getDisplayVsyncPeriod, (PhysicalDisplayId),
+ (const, override));
+ MOCK_METHOD(status_t, setActiveModeWithConstraints,
+ (PhysicalDisplayId, hal::HWConfigId, const hal::VsyncPeriodChangeConstraints&,
+ hal::VsyncPeriodChangeTimeline*),
+ (override));
+ MOCK_METHOD(status_t, setBootDisplayMode, (PhysicalDisplayId, hal::HWConfigId), (override));
+ MOCK_METHOD(status_t, clearBootDisplayMode, (PhysicalDisplayId), (override));
+ MOCK_METHOD(std::optional<hal::HWConfigId>, getPreferredBootDisplayMode, (PhysicalDisplayId),
+ (override));
+
+ MOCK_METHOD(std::vector<aidl::android::hardware::graphics::common::HdrConversionCapability>,
+ getHdrConversionCapabilities, (), (const, override));
+ MOCK_METHOD(status_t, setHdrConversionStrategy,
+ (aidl::android::hardware::graphics::common::HdrConversionStrategy,
+ aidl::android::hardware::graphics::common::Hdr*),
+ (override));
+ MOCK_METHOD(status_t, setAutoLowLatencyMode, (PhysicalDisplayId, bool), (override));
+ MOCK_METHOD(status_t, getSupportedContentTypes,
+ (PhysicalDisplayId, std::vector<hal::ContentType>*), (const, override));
+ MOCK_METHOD(status_t, setContentType, (PhysicalDisplayId, hal::ContentType)), (override);
+ MOCK_METHOD((const std::unordered_map<std::string, bool>&), getSupportedLayerGenericMetadata,
+ (), (const, override));
+ MOCK_METHOD(void, dump, (std::string&), (const, override));
+ MOCK_METHOD(void, dumpOverlayProperties, (std::string&), (const, override));
+ MOCK_METHOD(android::Hwc2::Composer*, getComposer, (), (const, override));
+
+ MOCK_METHOD(hal::HWDisplayId, getPrimaryHwcDisplayId, (), (const, override));
+ MOCK_METHOD(PhysicalDisplayId, getPrimaryDisplayId, (), (const, override));
+ MOCK_METHOD(bool, isHeadless, (), (const, override));
+
+ MOCK_METHOD(std::optional<PhysicalDisplayId>, toPhysicalDisplayId, (hal::HWDisplayId),
+ (const, override));
+ MOCK_METHOD(std::optional<hal::HWDisplayId>, fromPhysicalDisplayId, (PhysicalDisplayId),
+ (const, override));
+ MOCK_METHOD(status_t, getDisplayDecorationSupport,
+ (PhysicalDisplayId,
+ std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
+ support),
+ (override));
+ MOCK_METHOD(status_t, setIdleTimerEnabled, (PhysicalDisplayId, std::chrono::milliseconds),
+ (override));
+ MOCK_METHOD(bool, hasDisplayIdleTimerCapability, (PhysicalDisplayId), (const, override));
+ MOCK_METHOD(Hwc2::AidlTransform, getPhysicalDisplayOrientation, (PhysicalDisplayId),
+ (const, override));
+ MOCK_METHOD(bool, getValidateSkipped, (HalDisplayId), (const, override));
+ MOCK_METHOD(const aidl::android::hardware::graphics::composer3::OverlayProperties&,
+ getOverlaySupport, (), (const, override));
+ MOCK_METHOD(status_t, setRefreshRateChangedCallbackDebugEnabled, (PhysicalDisplayId, bool));
+ MOCK_METHOD(status_t, notifyExpectedPresent, (PhysicalDisplayId, TimePoint, Fps));
+ MOCK_METHOD(HWC2::Display::LutFileDescriptorMapper&, getLutFileDescriptorMapper, (),
+ (override));
+};
+
+} // namespace android::mock
diff --git a/services/vibratorservice/VibratorHalWrapper.cpp b/services/vibratorservice/VibratorHalWrapper.cpp
index b06ee3b..3ddc4f2 100644
--- a/services/vibratorservice/VibratorHalWrapper.cpp
+++ b/services/vibratorservice/VibratorHalWrapper.cpp
@@ -29,11 +29,11 @@
using aidl::android::hardware::vibrator::Braking;
using aidl::android::hardware::vibrator::CompositeEffect;
using aidl::android::hardware::vibrator::CompositePrimitive;
+using aidl::android::hardware::vibrator::CompositePwleV2;
using aidl::android::hardware::vibrator::Effect;
using aidl::android::hardware::vibrator::EffectStrength;
+using aidl::android::hardware::vibrator::FrequencyAccelerationMapEntry;
using aidl::android::hardware::vibrator::PrimitivePwle;
-using aidl::android::hardware::vibrator::PwleV2OutputMapEntry;
-using aidl::android::hardware::vibrator::PwleV2Primitive;
using aidl::android::hardware::vibrator::VendorEffect;
using std::chrono::milliseconds;
@@ -131,8 +131,7 @@
return HalResult<void>::unsupported();
}
-HalResult<void> HalWrapper::composePwleV2(const std::vector<PwleV2Primitive>&,
- const std::function<void()>&) {
+HalResult<void> HalWrapper::composePwleV2(const CompositePwleV2&, const std::function<void()>&) {
ALOGV("Skipped composePwleV2 because it's not available in Vibrator HAL");
return HalResult<void>::unsupported();
}
@@ -243,11 +242,11 @@
return HalResult<milliseconds>::unsupported();
}
-HalResult<std::vector<PwleV2OutputMapEntry>>
+HalResult<std::vector<FrequencyAccelerationMapEntry>>
HalWrapper::getFrequencyToOutputAccelerationMapInternal() {
ALOGV("Skipped getFrequencyToOutputAccelerationMapInternal because it's not "
"available in Vibrator HAL");
- return HalResult<std::vector<PwleV2OutputMapEntry>>::unsupported();
+ return HalResult<std::vector<FrequencyAccelerationMapEntry>>::unsupported();
}
// -------------------------------------------------------------------------------------------------
@@ -360,7 +359,7 @@
return HalResultFactory::fromStatus(getHal()->composePwle(primitives, cb));
}
-HalResult<void> AidlHalWrapper::composePwleV2(const std::vector<PwleV2Primitive>& composite,
+HalResult<void> AidlHalWrapper::composePwleV2(const CompositePwleV2& composite,
const std::function<void()>& completionCallback) {
// This method should always support callbacks, so no need to double check.
auto cb = ndk::SharedRefBase::make<HalCallbackWrapper>(completionCallback);
@@ -498,13 +497,13 @@
return HalResultFactory::fromStatus<milliseconds>(std::move(status), milliseconds(durationMs));
}
-HalResult<std::vector<PwleV2OutputMapEntry>>
+HalResult<std::vector<FrequencyAccelerationMapEntry>>
AidlHalWrapper::getFrequencyToOutputAccelerationMapInternal() {
- std::vector<PwleV2OutputMapEntry> frequencyToOutputAccelerationMap;
- auto status =
- getHal()->getPwleV2FrequencyToOutputAccelerationMap(&frequencyToOutputAccelerationMap);
+ std::vector<FrequencyAccelerationMapEntry> frequencyToOutputAccelerationMap;
+ auto status = getHal()->getFrequencyToOutputAccelerationMap(&frequencyToOutputAccelerationMap);
return HalResultFactory::fromStatus<
- std::vector<PwleV2OutputMapEntry>>(std::move(status), frequencyToOutputAccelerationMap);
+ std::vector<FrequencyAccelerationMapEntry>>(std::move(status),
+ frequencyToOutputAccelerationMap);
}
std::shared_ptr<Aidl::IVibrator> AidlHalWrapper::getHal() {
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
index b2bfffc..339a6e1 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
@@ -243,7 +243,8 @@
using EffectStrength = aidl::android::hardware::vibrator::EffectStrength;
using CompositePrimitive = aidl::android::hardware::vibrator::CompositePrimitive;
using Braking = aidl::android::hardware::vibrator::Braking;
- using PwleV2OutputMapEntry = aidl::android::hardware::vibrator::PwleV2OutputMapEntry;
+ using FrequencyAccelerationMapEntry =
+ aidl::android::hardware::vibrator::FrequencyAccelerationMapEntry;
const HalResult<Capabilities> capabilities;
const HalResult<std::vector<Effect>> supportedEffects;
@@ -262,7 +263,7 @@
const HalResult<int32_t> maxEnvelopeEffectSize;
const HalResult<std::chrono::milliseconds> minEnvelopeEffectControlPointDuration;
const HalResult<std::chrono::milliseconds> maxEnvelopeEffectControlPointDuration;
- const HalResult<std::vector<PwleV2OutputMapEntry>> frequencyToOutputAccelerationMap;
+ const HalResult<std::vector<FrequencyAccelerationMapEntry>> frequencyToOutputAccelerationMap;
void logFailures() const {
logFailure<Capabilities>(capabilities, "getCapabilities");
@@ -286,8 +287,9 @@
"getMinEnvelopeEffectControlPointDuration");
logFailure<std::chrono::milliseconds>(maxEnvelopeEffectControlPointDuration,
"getMaxEnvelopeEffectControlPointDuration");
- logFailure<std::vector<PwleV2OutputMapEntry>>(frequencyToOutputAccelerationMap,
- "getfrequencyToOutputAccelerationMap");
+ logFailure<
+ std::vector<FrequencyAccelerationMapEntry>>(frequencyToOutputAccelerationMap,
+ "getfrequencyToOutputAccelerationMap");
}
bool shouldRetry() const {
@@ -365,8 +367,8 @@
HalResult<std::chrono::milliseconds>::transactionFailed(MSG);
HalResult<std::chrono::milliseconds> mMaxEnvelopeEffectControlPointDuration =
HalResult<std::chrono::milliseconds>::transactionFailed(MSG);
- HalResult<std::vector<Info::PwleV2OutputMapEntry>> mFrequencyToOutputAccelerationMap =
- HalResult<std::vector<Info::PwleV2OutputMapEntry>>::transactionFailed(MSG);
+ HalResult<std::vector<Info::FrequencyAccelerationMapEntry>> mFrequencyToOutputAccelerationMap =
+ HalResult<std::vector<Info::FrequencyAccelerationMapEntry>>::transactionFailed(MSG);
friend class HalWrapper;
};
@@ -381,8 +383,9 @@
using CompositeEffect = aidl::android::hardware::vibrator::CompositeEffect;
using Braking = aidl::android::hardware::vibrator::Braking;
using PrimitivePwle = aidl::android::hardware::vibrator::PrimitivePwle;
- using PwleV2Primitive = aidl::android::hardware::vibrator::PwleV2Primitive;
- using PwleV2OutputMapEntry = aidl::android::hardware::vibrator::PwleV2OutputMapEntry;
+ using CompositePwleV2 = aidl::android::hardware::vibrator::CompositePwleV2;
+ using FrequencyAccelerationMapEntry =
+ aidl::android::hardware::vibrator::FrequencyAccelerationMapEntry;
explicit HalWrapper(std::shared_ptr<CallbackScheduler> scheduler)
: mCallbackScheduler(std::move(scheduler)) {}
@@ -420,7 +423,7 @@
virtual HalResult<void> performPwleEffect(const std::vector<PrimitivePwle>& primitives,
const std::function<void()>& completionCallback);
- virtual HalResult<void> composePwleV2(const std::vector<PwleV2Primitive>& composite,
+ virtual HalResult<void> composePwleV2(const CompositePwleV2& composite,
const std::function<void()>& completionCallback);
protected:
@@ -450,7 +453,7 @@
virtual HalResult<int32_t> getMaxEnvelopeEffectSizeInternal();
virtual HalResult<std::chrono::milliseconds> getMinEnvelopeEffectControlPointDurationInternal();
virtual HalResult<std::chrono::milliseconds> getMaxEnvelopeEffectControlPointDurationInternal();
- virtual HalResult<std::vector<PwleV2OutputMapEntry>>
+ virtual HalResult<std::vector<FrequencyAccelerationMapEntry>>
getFrequencyToOutputAccelerationMapInternal();
private:
@@ -508,7 +511,7 @@
const std::vector<PrimitivePwle>& primitives,
const std::function<void()>& completionCallback) override final;
- HalResult<void> composePwleV2(const std::vector<PwleV2Primitive>& composite,
+ HalResult<void> composePwleV2(const CompositePwleV2& composite,
const std::function<void()>& completionCallback) override final;
protected:
@@ -532,8 +535,9 @@
override final;
HalResult<std::chrono::milliseconds> getMaxEnvelopeEffectControlPointDurationInternal()
override final;
- HalResult<std::vector<PwleV2OutputMapEntry>> getFrequencyToOutputAccelerationMapInternal()
- override final;
+
+ HalResult<std::vector<FrequencyAccelerationMapEntry>>
+ getFrequencyToOutputAccelerationMapInternal() override final;
private:
const reconnect_fn mReconnectFn;
diff --git a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
index d42aa56..c58e05c 100644
--- a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
@@ -34,12 +34,13 @@
using aidl::android::hardware::vibrator::Braking;
using aidl::android::hardware::vibrator::CompositeEffect;
using aidl::android::hardware::vibrator::CompositePrimitive;
+using aidl::android::hardware::vibrator::CompositePwleV2;
using aidl::android::hardware::vibrator::Effect;
using aidl::android::hardware::vibrator::EffectStrength;
+using aidl::android::hardware::vibrator::FrequencyAccelerationMapEntry;
using aidl::android::hardware::vibrator::IVibrator;
using aidl::android::hardware::vibrator::IVibratorCallback;
using aidl::android::hardware::vibrator::PrimitivePwle;
-using aidl::android::hardware::vibrator::PwleV2OutputMapEntry;
using aidl::android::hardware::vibrator::PwleV2Primitive;
using aidl::android::hardware::vibrator::VendorEffect;
using aidl::android::os::PersistableBundle;
@@ -243,11 +244,11 @@
std::vector<CompositePrimitive> supportedPrimitives = {CompositePrimitive::CLICK};
std::vector<Braking> supportedBraking = {Braking::CLAB};
std::vector<float> amplitudes = {0.f, 1.f, 0.f};
- std::vector<PwleV2OutputMapEntry>
- frequencyToOutputAccelerationMap{PwleV2OutputMapEntry(/*frequency=*/30.0f,
- /*maxOutputAcceleration=*/0.2),
- PwleV2OutputMapEntry(/*frequency=*/60.0f,
- /*maxOutputAcceleration=*/0.8)};
+ std::vector<FrequencyAccelerationMapEntry> frequencyToOutputAccelerationMap{
+ FrequencyAccelerationMapEntry(/*frequency=*/30.0f,
+ /*maxOutputAcceleration=*/0.2),
+ FrequencyAccelerationMapEntry(/*frequency=*/60.0f,
+ /*maxOutputAcceleration=*/0.8)};
std::vector<std::chrono::milliseconds> primitiveDurations;
constexpr auto primitiveRange = ndk::enum_range<CompositePrimitive>();
@@ -329,7 +330,7 @@
.WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY)))
.WillOnce(DoAll(SetArgPointee<0>(PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS),
Return(ndk::ScopedAStatus::ok())));
- EXPECT_CALL(*mMockHal.get(), getPwleV2FrequencyToOutputAccelerationMap(_))
+ EXPECT_CALL(*mMockHal.get(), getFrequencyToOutputAccelerationMap(_))
.Times(Exactly(2))
.WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY)))
.WillOnce(DoAll(SetArgPointee<0>(frequencyToOutputAccelerationMap),
@@ -391,11 +392,11 @@
constexpr int32_t PWLE_V2_MAX_ALLOWED_PRIMITIVE_MIN_DURATION_MS = 20;
constexpr int32_t PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS = 1000;
std::vector<Effect> supportedEffects = {Effect::CLICK, Effect::TICK};
- std::vector<PwleV2OutputMapEntry>
- frequencyToOutputAccelerationMap{PwleV2OutputMapEntry(/*frequency=*/30.0f,
- /*maxOutputAcceleration=*/0.2),
- PwleV2OutputMapEntry(/*frequency=*/60.0f,
- /*maxOutputAcceleration=*/0.8)};
+ std::vector<FrequencyAccelerationMapEntry> frequencyToOutputAccelerationMap{
+ FrequencyAccelerationMapEntry(/*frequency=*/30.0f,
+ /*maxOutputAcceleration=*/0.2),
+ FrequencyAccelerationMapEntry(/*frequency=*/60.0f,
+ /*maxOutputAcceleration=*/0.8)};
EXPECT_CALL(*mMockHal.get(), getCapabilities(_))
.Times(Exactly(1))
@@ -451,7 +452,7 @@
.Times(Exactly(1))
.WillOnce(DoAll(SetArgPointee<0>(PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS),
Return(ndk::ScopedAStatus::ok())));
- EXPECT_CALL(*mMockHal.get(), getPwleV2FrequencyToOutputAccelerationMap(_))
+ EXPECT_CALL(*mMockHal.get(), getFrequencyToOutputAccelerationMap(_))
.Times(Exactly(1))
.WillOnce(DoAll(SetArgPointee<0>(frequencyToOutputAccelerationMap),
Return(ndk::ScopedAStatus::ok())));
@@ -754,7 +755,8 @@
}
TEST_F(VibratorHalWrapperAidlTest, TestComposePwleV2) {
- auto pwleEffect = {
+ CompositePwleV2 composite;
+ composite.pwlePrimitives = {
PwleV2Primitive(/*amplitude=*/0.2, /*frequency=*/50, /*time=*/100),
PwleV2Primitive(/*amplitude=*/0.5, /*frequency=*/150, /*time=*/100),
PwleV2Primitive(/*amplitude=*/0.8, /*frequency=*/250, /*time=*/100),
@@ -773,17 +775,17 @@
std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
- auto result = mWrapper->composePwleV2(pwleEffect, callback);
+ auto result = mWrapper->composePwleV2(composite, callback);
ASSERT_TRUE(result.isUnsupported());
// Callback not triggered on failure
ASSERT_EQ(0, *callbackCounter.get());
- result = mWrapper->composePwleV2(pwleEffect, callback);
+ result = mWrapper->composePwleV2(composite, callback);
ASSERT_TRUE(result.isFailed());
// Callback not triggered for unsupported
ASSERT_EQ(0, *callbackCounter.get());
- result = mWrapper->composePwleV2(pwleEffect, callback);
+ result = mWrapper->composePwleV2(composite, callback);
ASSERT_TRUE(result.isOk());
ASSERT_EQ(1, *callbackCounter.get());
}
diff --git a/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp b/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
index d6dab8d..04dbe4e 100644
--- a/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
@@ -36,6 +36,7 @@
using aidl::android::hardware::vibrator::Braking;
using aidl::android::hardware::vibrator::CompositeEffect;
using aidl::android::hardware::vibrator::CompositePrimitive;
+using aidl::android::hardware::vibrator::CompositePwleV2;
using aidl::android::hardware::vibrator::Effect;
using aidl::android::hardware::vibrator::EffectStrength;
using aidl::android::hardware::vibrator::IVibrator;
@@ -380,7 +381,8 @@
}
TEST_F(VibratorHalWrapperHidlV1_0Test, TestComposePwleV2Unsupported) {
- auto pwleEffect = {
+ CompositePwleV2 composite;
+ composite.pwlePrimitives = {
PwleV2Primitive(/*amplitude=*/0.2, /*frequency=*/50, /*time=*/100),
PwleV2Primitive(/*amplitude=*/0.5, /*frequency=*/150, /*time=*/100),
PwleV2Primitive(/*amplitude=*/0.8, /*frequency=*/250, /*time=*/100),
@@ -389,7 +391,7 @@
std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
- ASSERT_TRUE(mWrapper->composePwleV2(pwleEffect, callback).isUnsupported());
+ ASSERT_TRUE(mWrapper->composePwleV2(composite, callback).isUnsupported());
// No callback is triggered.
ASSERT_EQ(0, *callbackCounter.get());
diff --git a/services/vibratorservice/test/test_mocks.h b/services/vibratorservice/test/test_mocks.h
index 5e09084..ba273be 100644
--- a/services/vibratorservice/test/test_mocks.h
+++ b/services/vibratorservice/test/test_mocks.h
@@ -36,13 +36,13 @@
using aidl::android::hardware::vibrator::Braking;
using aidl::android::hardware::vibrator::CompositeEffect;
using aidl::android::hardware::vibrator::CompositePrimitive;
+using aidl::android::hardware::vibrator::CompositePwleV2;
using aidl::android::hardware::vibrator::Effect;
using aidl::android::hardware::vibrator::EffectStrength;
+using aidl::android::hardware::vibrator::FrequencyAccelerationMapEntry;
using aidl::android::hardware::vibrator::IVibrator;
using aidl::android::hardware::vibrator::IVibratorCallback;
using aidl::android::hardware::vibrator::PrimitivePwle;
-using aidl::android::hardware::vibrator::PwleV2OutputMapEntry;
-using aidl::android::hardware::vibrator::PwleV2Primitive;
using aidl::android::hardware::vibrator::VendorEffect;
// -------------------------------------------------------------------------------------------------
@@ -91,16 +91,15 @@
MOCK_METHOD(ndk::ScopedAStatus, getPwlePrimitiveDurationMax, (int32_t * ret), (override));
MOCK_METHOD(ndk::ScopedAStatus, getPwleCompositionSizeMax, (int32_t * ret), (override));
MOCK_METHOD(ndk::ScopedAStatus, getSupportedBraking, (std::vector<Braking> * ret), (override));
- MOCK_METHOD(ndk::ScopedAStatus, getPwleV2FrequencyToOutputAccelerationMap,
- (std::vector<PwleV2OutputMapEntry> * ret), (override));
+ MOCK_METHOD(ndk::ScopedAStatus, getFrequencyToOutputAccelerationMap,
+ (std::vector<FrequencyAccelerationMapEntry> * ret), (override));
MOCK_METHOD(ndk::ScopedAStatus, getPwleV2PrimitiveDurationMaxMillis, (int32_t* ret),
(override));
MOCK_METHOD(ndk::ScopedAStatus, getPwleV2PrimitiveDurationMinMillis, (int32_t* ret),
(override));
MOCK_METHOD(ndk::ScopedAStatus, getPwleV2CompositionSizeMax, (int32_t* ret), (override));
MOCK_METHOD(ndk::ScopedAStatus, composePwleV2,
- (const std::vector<PwleV2Primitive>& e,
- const std::shared_ptr<IVibratorCallback>& cb),
+ (const CompositePwleV2& e, const std::shared_ptr<IVibratorCallback>& cb),
(override));
MOCK_METHOD(ndk::ScopedAStatus, getInterfaceVersion, (int32_t*), (override));
MOCK_METHOD(ndk::ScopedAStatus, getInterfaceHash, (std::string*), (override));