Merge "Reimplement Chromium's OneEuroFilter to InputConsumer" into main
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/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index d24edc4..b012243 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1841,6 +1841,11 @@
RunCommand("DUMP VENDOR RIL LOGS", {"vril-dump"}, options.Build());
}
+ /* Dump USB information */
+ RunCommand("typec_connector_class", {"typec_connector_class"},
+ CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
+ RunCommand("lsusb", {"lsusb"}, CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
+
printf("========================================================\n");
printf("== Android Framework Services\n");
printf("========================================================\n");
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/data/etc/go_handheld_core_hardware.xml b/data/etc/go_handheld_core_hardware.xml
index 8df7fdb..a092842 100644
--- a/data/etc/go_handheld_core_hardware.xml
+++ b/data/etc/go_handheld_core_hardware.xml
@@ -51,6 +51,9 @@
<!-- Feature to specify if the device supports adding device admins. -->
<feature name="android.software.device_admin" />
+ <!-- Feature to specify if the device support managed users. -->
+ <feature name="android.software.managed_users" />
+
<!-- Devices with all optimizations required to support VR Mode and
pass all CDD requirements for this feature may include
android.hardware.vr.high_performance -->
diff --git a/include/android/performance_hint.h b/include/android/performance_hint.h
index 3f32a5a..3486e9b 100644
--- a/include/android/performance_hint.h
+++ b/include/android/performance_hint.h
@@ -52,7 +52,6 @@
* - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
*/
-#include <android/api-level.h>
#include <stdbool.h>
#include <stdint.h>
#include <unistd.h>
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index 8d61e77..fe38e86 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -763,6 +763,69 @@
__INTRODUCED_IN(31);
/**
+ * Sets the intended frame rate for the given \a surface_control.
+ *
+ * On devices that are capable of running the display at different frame rates,
+ * the system may choose a display refresh rate to better match this surface's frame
+ * rate. Usage of this API won't introduce frame rate throttling, or affect other
+ * aspects of the application's frame production pipeline. However, because the system
+ * may change the display refresh rate, calls to this function may result in changes
+ * to Choreographer callback timings, and changes to the time interval at which the
+ * system releases buffers back to the application.
+ *
+ * You can register for changes in the refresh rate using
+ * \a AChoreographer_registerRefreshRateCallback.
+ *
+ * See ASurfaceTransaction_clearFrameRate().
+ *
+ * Available since API level 36.
+ *
+ * \param desiredMinRate The desired minimum frame rate (inclusive) for the surface, specifying that
+ * the surface prefers the device render rate to be at least `desiredMinRate`.
+ *
+ * <p>Set `desiredMinRate` = `desiredMaxRate` to indicate the surface prefers an exact frame rate.
+ *
+ * <p>Set `desiredMinRate` = 0 to indicate the surface has no preference
+ * and any frame rate is acceptable.
+ *
+ * <p>The value should be greater than or equal to 0.
+ *
+ * \param desiredMaxRate The desired maximum frame rate (inclusive) for the surface, specifying that
+ * the surface prefers the device render rate to be at most `desiredMaxRate`.
+ *
+ * <p>Set `desiredMaxRate` = `desiredMinRate` to indicate the surface prefers an exact frame rate.
+ *
+ * <p>Set `desiredMaxRate` = positive infinity to indicate the surface has no preference
+ * and any frame rate is acceptable.
+ *
+ * <p>The value should be greater than or equal to `desiredMinRate`.
+ *
+ * \param fixedSourceRate The "fixed source" frame rate of the surface if the content has an
+ * inherently fixed frame rate, e.g. a video that has a specific frame rate.
+ *
+ * <p>When the frame rate chosen for the surface is the `fixedSourceRate` or a
+ * multiple, the surface can render without frame pulldown, for optimal smoothness. For
+ * example, a 30 fps video (`fixedSourceRate`=30) renders just as smoothly on 30 fps,
+ * 60 fps, 90 fps, 120 fps, and so on.
+ *
+ * <p>Setting the fixed source rate can also be used together with a desired
+ * frame rate min and max via setting `desiredMinRate` and `desiredMaxRate`. This still
+ * means the surface's content has a fixed frame rate of `fixedSourceRate`, but additionally
+ * specifies the preference to be in the range [`desiredMinRate`, `desiredMaxRate`]. For example, an
+ * app might want to specify there is 30 fps video (`fixedSourceRate`=30) as well as a smooth
+ * animation on the same surface which looks good when drawing within a frame rate range such as
+ * [`desiredMinRate`, `desiredMaxRate`] = [60,120].
+ *
+ * \param changeFrameRateStrategy Whether display refresh rate transitions caused by this surface
+ * should be seamless. A seamless transition is one that doesn't have any visual interruptions, such
+ * as a black screen for a second or two.
+ */
+void ASurfaceTransaction_setFrameRateParams(
+ ASurfaceTransaction* _Nonnull transaction, ASurfaceControl* _Nonnull surface_control,
+ float desiredMinRate, float desiredMaxRate, float fixedSourceRate,
+ ANativeWindow_ChangeFrameRateStrategy changeFrameRateStrategy) __INTRODUCED_IN(36);
+
+/**
* Clears the frame rate which is set for \a surface_control.
*
* This is equivalent to calling
diff --git a/libs/battery/LongArrayMultiStateCounter.cpp b/libs/battery/LongArrayMultiStateCounter.cpp
index 125cfaf..35c40ab 100644
--- a/libs/battery/LongArrayMultiStateCounter.cpp
+++ b/libs/battery/LongArrayMultiStateCounter.cpp
@@ -21,59 +21,135 @@
namespace android {
namespace battery {
+Uint64ArrayRW::Uint64ArrayRW(const Uint64Array ©) : Uint64Array(copy.size()) {
+ if (mSize != 0 && copy.data() != nullptr) {
+ mData = new uint64_t[mSize];
+ memcpy(mData, copy.data(), mSize * sizeof(uint64_t));
+ } else {
+ mData = nullptr;
+ }
+}
+
+uint64_t *Uint64ArrayRW::dataRW() {
+ if (mData == nullptr) {
+ mData = new uint64_t[mSize];
+ memset(mData, 0, mSize * sizeof(uint64_t));
+ }
+ return mData;
+}
+
+Uint64ArrayRW &Uint64ArrayRW::operator=(const Uint64Array &t) {
+ if (t.size() != mSize) {
+ delete[] mData;
+ mSize = t.size();
+ mData = nullptr;
+ }
+ if (mSize != 0) {
+ if (t.data() != nullptr) {
+ mData = new uint64_t[mSize];
+ memcpy(mData, t.data(), mSize * sizeof(uint64_t));
+ } else {
+ mData = nullptr;
+ }
+ }
+ return *this;
+}
+
+std::ostream &operator<<(std::ostream &os, const Uint64Array &v) {
+ os << "{";
+ const uint64_t *data = v.data();
+ if (data != nullptr) {
+ bool first = true;
+ for (size_t i = 0; i < v.size(); i++) {
+ if (!first) {
+ os << ", ";
+ }
+ os << data[i];
+ first = false;
+ }
+ }
+ os << "}";
+ return os;
+}
+
+// Convenience constructor for tests
+Uint64ArrayRW::Uint64ArrayRW(std::initializer_list<uint64_t> init) : Uint64Array(init.size()) {
+ mData = new uint64_t[mSize];
+ memcpy(mData, init.begin(), mSize * sizeof(uint64_t));
+}
+
+// Used in tests only.
+bool Uint64Array::operator==(const Uint64Array &other) const {
+ if (size() != other.size()) {
+ return false;
+ }
+ const uint64_t* thisData = data();
+ const uint64_t* thatData = other.data();
+ for (size_t i = 0; i < mSize; i++) {
+ const uint64_t v1 = thisData != nullptr ? thisData[i] : 0;
+ const uint64_t v2 = thatData != nullptr ? thatData[i] : 0;
+ if (v1 != v2) {
+ return false;
+ }
+ }
+ return true;
+}
+
template <>
-bool LongArrayMultiStateCounter::delta(const std::vector<uint64_t>& previousValue,
- const std::vector<uint64_t>& newValue,
- std::vector<uint64_t>* outValue) const {
+void LongArrayMultiStateCounter::add(Uint64ArrayRW *value1, const Uint64Array &value2,
+ const uint64_t numerator, const uint64_t denominator) const {
+ const uint64_t* data2 = value2.data();
+ if (data2 == nullptr) {
+ return;
+ }
+
+ uint64_t* data1 = value1->dataRW();
+ size_t size = value2.size();
+ if (numerator != denominator) {
+ for (size_t i = 0; i < size; i++) {
+ // The caller ensures that denominator != 0
+ data1[i] += data2[i] * numerator / denominator;
+ }
+ } else {
+ for (size_t i = 0; i < size; i++) {
+ data1[i] += data2[i];
+ }
+ }
+}
+
+template<>
+bool LongArrayMultiStateCounter::delta(const Uint64ArrayRW &previousValue,
+ const Uint64Array &newValue, Uint64ArrayRW *outValue) const {
size_t size = previousValue.size();
if (newValue.size() != size) {
- ALOGE("Incorrect array size: %d, should be %d", (int)newValue.size(), (int)size);
+ ALOGE("Incorrect array size: %d, should be %d", (int) newValue.size(), (int) size);
+ return false;
+ }
+ if (outValue->size() != size) {
+ ALOGE("Incorrect outValue size: %d, should be %d", (int) outValue->size(), (int) size);
return false;
}
bool is_delta_valid = true;
- for (int i = size - 1; i >= 0; i--) {
- if (newValue[i] >= previousValue[i]) {
- (*outValue)[i] = newValue[i] - previousValue[i];
- } else {
- (*outValue)[i] = 0;
+ const uint64_t *prevData = previousValue.data();
+ const uint64_t *newData = newValue.data();
+ uint64_t *outData = outValue->dataRW();
+ for (size_t i = 0; i < size; i++) {
+ if (prevData == nullptr) {
+ if (newData == nullptr) {
+ outData[i] = 0;
+ } else {
+ outData[i] = newData[i];
+ }
+ } else if (newData == nullptr || newData[i] < prevData[i]) {
+ outData[i] = 0;
is_delta_valid = false;
+ } else {
+ outData[i] = newData[i] - prevData[i];
}
}
return is_delta_valid;
}
-template <>
-void LongArrayMultiStateCounter::add(std::vector<uint64_t>* value1,
- const std::vector<uint64_t>& value2, const uint64_t numerator,
- const uint64_t denominator) const {
- if (numerator != denominator) {
- for (int i = value2.size() - 1; i >= 0; i--) {
- // The caller ensures that denominator != 0
- (*value1)[i] += value2[i] * numerator / denominator;
- }
- } else {
- for (int i = value2.size() - 1; i >= 0; i--) {
- (*value1)[i] += value2[i];
- }
- }
-}
-
-template <>
-std::string LongArrayMultiStateCounter::valueToString(const std::vector<uint64_t>& v) const {
- std::stringstream s;
- s << "{";
- bool first = true;
- for (uint64_t n : v) {
- if (!first) {
- s << ", ";
- }
- s << n;
- first = false;
- }
- s << "}";
- return s.str();
-}
-
} // namespace battery
} // namespace android
diff --git a/libs/battery/LongArrayMultiStateCounter.h b/libs/battery/LongArrayMultiStateCounter.h
index f3439f6..e00c968 100644
--- a/libs/battery/LongArrayMultiStateCounter.h
+++ b/libs/battery/LongArrayMultiStateCounter.h
@@ -23,7 +23,66 @@
namespace android {
namespace battery {
-typedef MultiStateCounter<std::vector<uint64_t>> LongArrayMultiStateCounter;
+/**
+ * Wrapper for an array of uint64's.
+ */
+class Uint64Array {
+ protected:
+ size_t mSize;
+
+ public:
+ Uint64Array() : Uint64Array(0) {}
+
+ Uint64Array(size_t size) : mSize(size) {}
+
+ virtual ~Uint64Array() {}
+
+ size_t size() const { return mSize; }
+
+ /**
+ * Returns the wrapped array.
+ *
+ * Nullable! Null should be interpreted the same as an array of zeros
+ */
+ virtual const uint64_t *data() const { return nullptr; }
+
+ friend std::ostream &operator<<(std::ostream &os, const Uint64Array &v);
+
+ // Test API
+ bool operator==(const Uint64Array &other) const;
+};
+
+/**
+ * Mutable version of Uint64Array.
+ */
+class Uint64ArrayRW: public Uint64Array {
+ uint64_t* mData;
+
+public:
+ Uint64ArrayRW() : Uint64ArrayRW(0) {}
+
+ Uint64ArrayRW(size_t size) : Uint64Array(size), mData(nullptr) {}
+
+ Uint64ArrayRW(const Uint64Array ©);
+
+ // Need an explicit copy constructor. In the initialization context C++ does not understand that
+ // a Uint64ArrayRW is a Uint64Array.
+ Uint64ArrayRW(const Uint64ArrayRW ©) : Uint64ArrayRW((const Uint64Array &) copy) {}
+
+ // Test API
+ Uint64ArrayRW(std::initializer_list<uint64_t> init);
+
+ ~Uint64ArrayRW() override { delete[] mData; }
+
+ const uint64_t *data() const override { return mData; }
+
+ // NonNull. Will initialize the wrapped array if it is null.
+ uint64_t *dataRW();
+
+ Uint64ArrayRW &operator=(const Uint64Array &t);
+};
+
+typedef MultiStateCounter<Uint64ArrayRW, Uint64Array> LongArrayMultiStateCounter;
} // namespace battery
} // namespace android
diff --git a/libs/battery/LongArrayMultiStateCounterTest.cpp b/libs/battery/LongArrayMultiStateCounterTest.cpp
index e4e6b2a..1c74e3f 100644
--- a/libs/battery/LongArrayMultiStateCounterTest.cpp
+++ b/libs/battery/LongArrayMultiStateCounterTest.cpp
@@ -24,25 +24,25 @@
class LongArrayMultiStateCounterTest : public testing::Test {};
TEST_F(LongArrayMultiStateCounterTest, stateChange) {
- LongArrayMultiStateCounter testCounter(2, std::vector<uint64_t>(4));
- testCounter.updateValue(std::vector<uint64_t>({0, 0, 0, 0}), 1000);
+ LongArrayMultiStateCounter testCounter(2, Uint64Array(4));
+ testCounter.updateValue(Uint64ArrayRW({0, 0, 0, 0}), 1000);
testCounter.setState(0, 1000);
testCounter.setState(1, 2000);
- testCounter.updateValue(std::vector<uint64_t>({100, 200, 300, 400}), 3000);
+ testCounter.updateValue(Uint64ArrayRW({100, 200, 300, 400}), 3000);
// Time was split in half between the two states, so the counts will be split 50:50 too
- EXPECT_EQ(std::vector<uint64_t>({50, 100, 150, 200}), testCounter.getCount(0));
- EXPECT_EQ(std::vector<uint64_t>({50, 100, 150, 200}), testCounter.getCount(1));
+ EXPECT_EQ(Uint64ArrayRW({50, 100, 150, 200}), testCounter.getCount(0));
+ EXPECT_EQ(Uint64ArrayRW({50, 100, 150, 200}), testCounter.getCount(1));
}
TEST_F(LongArrayMultiStateCounterTest, accumulation) {
- LongArrayMultiStateCounter testCounter(2, std::vector<uint64_t>(4));
- testCounter.updateValue(std::vector<uint64_t>({0, 0, 0, 0}), 1000);
+ LongArrayMultiStateCounter testCounter(2, Uint64Array(4));
+ testCounter.updateValue(Uint64ArrayRW({0, 0, 0, 0}), 1000);
testCounter.setState(0, 1000);
testCounter.setState(1, 2000);
- testCounter.updateValue(std::vector<uint64_t>({100, 200, 300, 400}), 3000);
+ testCounter.updateValue(Uint64ArrayRW({100, 200, 300, 400}), 3000);
testCounter.setState(0, 4000);
- testCounter.updateValue(std::vector<uint64_t>({200, 300, 400, 500}), 8000);
+ testCounter.updateValue(Uint64ArrayRW({200, 300, 400, 500}), 8000);
// The first delta is split 50:50:
// 0: {50, 100, 150, 200}
@@ -50,16 +50,16 @@
// The second delta is split 4:1
// 0: {80, 80, 80, 80}
// 1: {20, 20, 20, 20}
- EXPECT_EQ(std::vector<uint64_t>({130, 180, 230, 280}), testCounter.getCount(0));
- EXPECT_EQ(std::vector<uint64_t>({70, 120, 170, 220}), testCounter.getCount(1));
+ EXPECT_EQ(Uint64ArrayRW({130, 180, 230, 280}), testCounter.getCount(0));
+ EXPECT_EQ(Uint64ArrayRW({70, 120, 170, 220}), testCounter.getCount(1));
}
TEST_F(LongArrayMultiStateCounterTest, toString) {
- LongArrayMultiStateCounter testCounter(2, std::vector<uint64_t>(4));
- testCounter.updateValue(std::vector<uint64_t>({0, 0, 0, 0}), 1000);
+ LongArrayMultiStateCounter testCounter(2, Uint64Array(4));
+ testCounter.updateValue(Uint64ArrayRW({0, 0, 0, 0}), 1000);
testCounter.setState(0, 1000);
testCounter.setState(1, 2000);
- testCounter.updateValue(std::vector<uint64_t>({100, 200, 300, 400}), 3000);
+ testCounter.updateValue(Uint64ArrayRW({100, 200, 300, 400}), 3000);
EXPECT_STREQ("[0: {50, 100, 150, 200}, 1: {50, 100, 150, 200}] updated: 3000 currentState: 1",
testCounter.toString().c_str());
diff --git a/libs/battery/MultiStateCounter.h b/libs/battery/MultiStateCounter.h
index 04b7186..fadc4ff 100644
--- a/libs/battery/MultiStateCounter.h
+++ b/libs/battery/MultiStateCounter.h
@@ -35,12 +35,12 @@
typedef uint16_t state_t;
-template <class T>
+template <class T, class V>
class MultiStateCounter {
- uint16_t stateCount;
+ const uint16_t stateCount;
+ const V emptyValue;
state_t currentState;
time_t lastStateChangeTimestamp;
- T emptyValue;
T lastValue;
time_t lastUpdateTimestamp;
T deltaValue;
@@ -54,7 +54,7 @@
State* states;
public:
- MultiStateCounter(uint16_t stateCount, const T& emptyValue);
+ MultiStateCounter(uint16_t stateCount, const V& emptyValue);
virtual ~MultiStateCounter();
@@ -66,35 +66,35 @@
* Copies the current state and accumulated times-in-state from the source. Resets
* the accumulated value.
*/
- void copyStatesFrom(const MultiStateCounter<T>& source);
+ void copyStatesFrom(const MultiStateCounter<T, V> &source);
- void setValue(state_t state, const T& value);
+ void setValue(state_t state, const V& value);
/**
* Updates the value by distributing the delta from the previously set value
* among states according to their respective time-in-state.
* Returns the delta from the previously set value.
*/
- const T& updateValue(const T& value, time_t timestamp);
+ const V& updateValue(const V& value, time_t timestamp);
/**
* Updates the value by distributing the specified increment among states according
* to their respective time-in-state.
*/
- void incrementValue(const T& increment, time_t timestamp);
+ void incrementValue(const V& increment, time_t timestamp);
/**
* Adds the specified increment to the value for the current state, without affecting
* the last updated value or timestamp. Ignores partial time-in-state: the entirety of
* the increment is given to the current state.
*/
- void addValue(const T& increment);
+ void addValue(const V& increment);
void reset();
uint16_t getStateCount();
- const T& getCount(state_t state);
+ const V& getCount(state_t state);
std::string toString();
@@ -104,27 +104,25 @@
* Returns true iff the combination of previousValue and newValue is valid
* (newValue >= prevValue)
*/
- bool delta(const T& previousValue, const T& newValue, T* outValue) const;
+ bool delta(const T& previousValue, const V& newValue, T* outValue) const;
/**
* Adds value2 to value1 and stores the result in value1. Denominator is
* guaranteed to be non-zero.
*/
- void add(T* value1, const T& value2, const uint64_t numerator,
+ void add(T* value1, const V& value2, const uint64_t numerator,
const uint64_t denominator) const;
-
- std::string valueToString(const T& value) const;
};
// ---------------------- MultiStateCounter Implementation -------------------------
// Since MultiStateCounter is a template, the implementation must be inlined.
-template <class T>
-MultiStateCounter<T>::MultiStateCounter(uint16_t stateCount, const T& emptyValue)
+template <class T, class V>
+MultiStateCounter<T, V>::MultiStateCounter(uint16_t stateCount, const V& emptyValue)
: stateCount(stateCount),
+ emptyValue(emptyValue),
currentState(0),
lastStateChangeTimestamp(-1),
- emptyValue(emptyValue),
lastValue(emptyValue),
lastUpdateTimestamp(-1),
deltaValue(emptyValue),
@@ -136,13 +134,13 @@
}
}
-template <class T>
-MultiStateCounter<T>::~MultiStateCounter() {
+template <class T, class V>
+MultiStateCounter<T, V>::~MultiStateCounter() {
delete[] states;
};
-template <class T>
-void MultiStateCounter<T>::setEnabled(bool enabled, time_t timestamp) {
+template <class T, class V>
+void MultiStateCounter<T, V>::setEnabled(bool enabled, time_t timestamp) {
if (enabled == isEnabled) {
return;
}
@@ -167,8 +165,8 @@
}
}
-template <class T>
-void MultiStateCounter<T>::setState(state_t state, time_t timestamp) {
+template <class T, class V>
+void MultiStateCounter<T, V>::setState(state_t state, time_t timestamp) {
if (isEnabled && lastStateChangeTimestamp >= 0 && lastUpdateTimestamp >= 0) {
// If the update arrived out-of-order, just push back the timestamp to
// avoid having the situation where timeInStateSinceUpdate > timeSinceUpdate
@@ -198,8 +196,8 @@
lastStateChangeTimestamp = timestamp;
}
-template <class T>
-void MultiStateCounter<T>::copyStatesFrom(const MultiStateCounter<T>& source) {
+template <class T, class V>
+void MultiStateCounter<T, V>::copyStatesFrom(const MultiStateCounter<T, V>& source) {
if (stateCount != source.stateCount) {
ALOGE("State count mismatch: %u vs. %u\n", stateCount, source.stateCount);
return;
@@ -214,14 +212,14 @@
lastUpdateTimestamp = source.lastUpdateTimestamp;
}
-template <class T>
-void MultiStateCounter<T>::setValue(state_t state, const T& value) {
+template <class T, class V>
+void MultiStateCounter<T, V>::setValue(state_t state, const V& value) {
states[state].counter = value;
}
-template <class T>
-const T& MultiStateCounter<T>::updateValue(const T& value, time_t timestamp) {
- T* returnValue = &emptyValue;
+template <class T, class V>
+const V& MultiStateCounter<T, V>::updateValue(const V& value, time_t timestamp) {
+ const V* returnValue = &emptyValue;
// If the counter is disabled, we ignore the update, except when the counter got disabled after
// the previous update, in which case we still need to pick up the residual delta.
@@ -250,8 +248,8 @@
}
} else {
std::stringstream str;
- str << "updateValue is called with a value " << valueToString(value)
- << ", which is lower than the previous value " << valueToString(lastValue)
+ str << "updateValue is called with a value " << value
+ << ", which is lower than the previous value " << lastValue
<< "\n";
ALOGE("%s", str.str().c_str());
@@ -276,23 +274,25 @@
return *returnValue;
}
-template <class T>
-void MultiStateCounter<T>::incrementValue(const T& increment, time_t timestamp) {
+template <class T, class V>
+void MultiStateCounter<T, V>::incrementValue(const V& increment, time_t timestamp) {
+// T newValue;
+// newValue = lastValue; // Copy assignment, not initialization.
T newValue = lastValue;
add(&newValue, increment, 1 /* numerator */, 1 /* denominator */);
updateValue(newValue, timestamp);
}
-template <class T>
-void MultiStateCounter<T>::addValue(const T& value) {
+template <class T, class V>
+void MultiStateCounter<T, V>::addValue(const V& value) {
if (!isEnabled) {
return;
}
add(&states[currentState].counter, value, 1 /* numerator */, 1 /* denominator */);
}
-template <class T>
-void MultiStateCounter<T>::reset() {
+template <class T, class V>
+void MultiStateCounter<T, V>::reset() {
lastStateChangeTimestamp = -1;
lastUpdateTimestamp = -1;
for (int i = 0; i < stateCount; i++) {
@@ -301,25 +301,26 @@
}
}
-template <class T>
-uint16_t MultiStateCounter<T>::getStateCount() {
+template <class T, class V>
+uint16_t MultiStateCounter<T, V>::getStateCount() {
return stateCount;
}
-template <class T>
-const T& MultiStateCounter<T>::getCount(state_t state) {
+template <class T, class V>
+const V& MultiStateCounter<T, V>::getCount(state_t state) {
return states[state].counter;
}
-template <class T>
-std::string MultiStateCounter<T>::toString() {
+template <class T, class V>
+std::string MultiStateCounter<T, V>::toString() {
std::stringstream str;
+// str << "LAST VALUE: " << valueToString(lastValue);
str << "[";
for (int i = 0; i < stateCount; i++) {
if (i != 0) {
str << ", ";
}
- str << i << ": " << valueToString(states[i].counter);
+ str << i << ": " << states[i].counter;
if (states[i].timeInStateSinceUpdate > 0) {
str << " timeInStateSinceUpdate: " << states[i].timeInStateSinceUpdate;
}
diff --git a/libs/battery/MultiStateCounterTest.cpp b/libs/battery/MultiStateCounterTest.cpp
index a51a38a..589b7fe 100644
--- a/libs/battery/MultiStateCounterTest.cpp
+++ b/libs/battery/MultiStateCounterTest.cpp
@@ -21,7 +21,7 @@
namespace android {
namespace battery {
-typedef MultiStateCounter<double> DoubleMultiStateCounter;
+typedef MultiStateCounter<double, double> DoubleMultiStateCounter;
template <>
bool DoubleMultiStateCounter::delta(const double& previousValue, const double& newValue,
@@ -41,11 +41,6 @@
}
}
-template <>
-std::string DoubleMultiStateCounter::valueToString(const double& v) const {
- return std::to_string(v);
-}
-
class MultiStateCounterTest : public testing::Test {};
TEST_F(MultiStateCounterTest, constructor) {
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 6903cb5..2ef642a 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -871,6 +871,10 @@
symbol_file: "libbinder_rpc_unstable.map.txt",
},
+ header_abi_checker: {
+ enabled: false,
+ },
+
// This library is intentionally limited to these targets, and it will be removed later.
// Do not expand the visibility.
visibility: [
diff --git a/libs/binder/BackendUnifiedServiceManager.cpp b/libs/binder/BackendUnifiedServiceManager.cpp
index 98a7555..d32eecd 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
@@ -104,7 +105,8 @@
};
bool BinderCacheWithInvalidation::isClientSideCachingEnabled(const std::string& serviceName) {
- if (ProcessState::self()->getThreadPoolMaxTotalThreadCount() <= 0) {
+ sp<ProcessState> self = ProcessState::selfOrNull();
+ if (!self || self->getThreadPoolMaxTotalThreadCount() <= 0) {
ALOGW("Thread Pool max thread count is 0. Cannot cache binder as linkToDeath cannot be "
"implemented. serviceName: %s",
serviceName.c_str());
@@ -118,10 +120,10 @@
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)) {
@@ -149,7 +151,7 @@
"caching_not_enabled");
}
}
- return binder::Status::ok();
+ return Status::ok();
}
bool BackendUnifiedServiceManager::returnIfCached(const std::string& serviceName,
@@ -171,25 +173,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);
@@ -200,14 +197,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()) {
@@ -217,16 +213,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;
@@ -242,7 +237,7 @@
}
*_out = in;
- return binder::Status::ok();
+ return Status::ok();
}
case os::Service::Tag::accessor: {
sp<IBinder> accessorBinder = in.get<os::Service::Tag::accessor>();
@@ -250,11 +245,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 {
@@ -267,11 +262,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());
@@ -279,53 +274,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 feb8470..abc0eda 100644
--- a/libs/binder/BackendUnifiedServiceManager.h
+++ b/libs/binder/BackendUnifiedServiceManager.h
@@ -121,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/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 32388db..39d8c24 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -561,8 +561,9 @@
sp<IBinder> svc = checkService(name);
if (svc != nullptr) return svc;
+ sp<ProcessState> self = ProcessState::selfOrNull();
const bool isVendorService =
- strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder") == 0;
+ self && strcmp(self->getDriverName().c_str(), "/dev/vndbinder") == 0;
constexpr auto timeout = 5s;
const auto startTime = std::chrono::steady_clock::now();
// Vendor code can't access system properties
@@ -579,7 +580,7 @@
const useconds_t sleepTime = gSystemBootCompleted ? 1000 : 100;
ALOGI("Waiting for service '%s' on '%s'...", String8(name).c_str(),
- ProcessState::self()->getDriverName().c_str());
+ self ? self->getDriverName().c_str() : "RPC accessors only");
int n = 0;
while (std::chrono::steady_clock::now() - startTime < timeout) {
@@ -661,7 +662,8 @@
if (Status status = realGetService(name, &out); !status.isOk()) {
ALOGW("Failed to getService in waitForService for %s: %s", name.c_str(),
status.toString8().c_str());
- if (0 == ProcessState::self()->getThreadPoolMaxTotalThreadCount()) {
+ sp<ProcessState> self = ProcessState::selfOrNull();
+ if (self && 0 == self->getThreadPoolMaxTotalThreadCount()) {
ALOGW("Got service, but may be racey because we could not wait efficiently for it. "
"Threadpool has 0 guaranteed threads. "
"Is the threadpool configured properly? "
@@ -695,9 +697,10 @@
if (waiter->mBinder != nullptr) return waiter->mBinder;
}
+ sp<ProcessState> self = ProcessState::selfOrNull();
ALOGW("Waited one second for %s (is service started? Number of threads started in the "
"threadpool: %zu. Are binder threads started and available?)",
- name.c_str(), ProcessState::self()->getThreadPoolMaxTotalThreadCount());
+ name.c_str(), self ? self->getThreadPoolMaxTotalThreadCount() : 0);
// Handle race condition for lazy services. Here is what can happen:
// - the service dies (not processed by init yet).
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/include_rpc_unstable/binder_rpc_unstable.hpp b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
index 392ebb5..48c0ea6 100644
--- a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
+++ b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
@@ -37,8 +37,12 @@
// Set `cid` to VMADDR_CID_LOCAL to only bind to the local vsock interface.
// Returns an opaque handle to the running server instance, or null if the server
// could not be started.
+// Set |port| to VMADDR_PORT_ANY to pick an available ephemeral port.
+// |assignedPort| will be set to the assigned port number if it is not null.
+// This will be the provided |port|, or the chosen available ephemeral port when
+// |port| is VMADDR_PORT_ANY.
[[nodiscard]] ARpcServer* ARpcServer_newVsock(AIBinder* service, unsigned int cid,
- unsigned int port);
+ unsigned int port, unsigned int* assignedPort);
// Starts a Unix domain RPC server with an open raw socket file descriptor
// and a given root IBinder object.
diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp
index 21537fc..a84a0c6 100644
--- a/libs/binder/libbinder_rpc_unstable.cpp
+++ b/libs/binder/libbinder_rpc_unstable.cpp
@@ -81,7 +81,8 @@
extern "C" {
#ifndef __TRUSTY__
-ARpcServer* ARpcServer_newVsock(AIBinder* service, unsigned int cid, unsigned int port) {
+ARpcServer* ARpcServer_newVsock(AIBinder* service, unsigned int cid, unsigned int port,
+ unsigned int* assignedPort) {
auto server = RpcServer::make();
unsigned int bindCid = VMADDR_CID_ANY; // bind to the remote interface
@@ -90,7 +91,7 @@
cid = VMADDR_CID_ANY; // no need for a connection filter
}
- if (status_t status = server->setupVsockServer(bindCid, port); status != OK) {
+ if (status_t status = server->setupVsockServer(bindCid, port, assignedPort); status != OK) {
ALOGE("Failed to set up vsock server with port %u error: %s", port,
statusToString(status).c_str());
return nullptr;
diff --git a/libs/binder/ndk/binder_rpc.cpp b/libs/binder/ndk/binder_rpc.cpp
index 07b8c40..53ab68e 100644
--- a/libs/binder/ndk/binder_rpc.cpp
+++ b/libs/binder/ndk/binder_rpc.cpp
@@ -104,8 +104,8 @@
};
ABinderRpc_AccessorProvider* ABinderRpc_registerAccessorProvider(
- ABinderRpc_AccessorProvider_getAccessorCallback provider, const char** instances,
- size_t numInstances, void* data,
+ ABinderRpc_AccessorProvider_getAccessorCallback provider,
+ const char* const* const instances, size_t numInstances, void* data,
ABinderRpc_AccessorProviderUserData_deleteCallback onDelete) {
if (provider == nullptr) {
ALOGE("Null provider passed to ABinderRpc_registerAccessorProvider");
@@ -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..7d54e2d 100644
--- a/libs/binder/ndk/include_platform/android/binder_rpc.h
+++ b/libs/binder/ndk/include_platform/android/binder_rpc.h
@@ -144,8 +144,9 @@
*/
ABinderRpc_AccessorProvider* _Nullable ABinderRpc_registerAccessorProvider(
ABinderRpc_AccessorProvider_getAccessorCallback _Nonnull provider,
- const char* _Nullable* _Nonnull instances, size_t numInstances, void* _Nullable data,
- ABinderRpc_AccessorProviderUserData_deleteCallback _Nullable onDelete) __INTRODUCED_IN(36);
+ const char* _Nullable const* const _Nonnull instances, size_t numInstances,
+ void* _Nullable data, ABinderRpc_AccessorProviderUserData_deleteCallback _Nullable onDelete)
+ __INTRODUCED_IN(36);
/**
* Remove an ABinderRpc_AccessorProvider from libbinder. This will remove references
@@ -287,6 +288,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/rpcbinder/src/server/android.rs b/libs/binder/rust/rpcbinder/src/server/android.rs
index 2ab3447..74ce315 100644
--- a/libs/binder/rust/rpcbinder/src/server/android.rs
+++ b/libs/binder/rust/rpcbinder/src/server/android.rs
@@ -18,7 +18,7 @@
use binder::{unstable_api::AsNative, SpIBinder};
use binder_rpc_unstable_bindgen::ARpcServer;
use foreign_types::{foreign_type, ForeignType, ForeignTypeRef};
-use std::ffi::CString;
+use std::ffi::{c_uint, CString};
use std::io::{Error, ErrorKind};
use std::os::unix::io::{IntoRawFd, OwnedFd};
@@ -42,18 +42,29 @@
/// Creates a binder RPC server, serving the supplied binder service implementation on the given
/// vsock port. Only connections from the given CID are accepted.
///
- // Set `cid` to libc::VMADDR_CID_ANY to accept connections from any client.
- // Set `cid` to libc::VMADDR_CID_LOCAL to only bind to the local vsock interface.
- pub fn new_vsock(mut service: SpIBinder, cid: u32, port: u32) -> Result<RpcServer, Error> {
+ /// Set `cid` to [`libc::VMADDR_CID_ANY`] to accept connections from any client.
+ /// Set `cid` to [`libc::VMADDR_CID_LOCAL`] to only bind to the local vsock interface.
+ /// Set `port` to [`libc::VMADDR_PORT_ANY`] to pick an ephemeral port.
+ /// The assigned port is returned with RpcServer.
+ pub fn new_vsock(
+ mut service: SpIBinder,
+ cid: u32,
+ port: u32,
+ ) -> Result<(RpcServer, u32 /* assigned_port */), Error> {
let service = service.as_native_mut();
+ let mut assigned_port: c_uint = 0;
// SAFETY: Service ownership is transferring to the server and won't be valid afterward.
// Plus the binder objects are threadsafe.
- unsafe {
+ let server = unsafe {
Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newVsock(
- service, cid, port,
- ))
- }
+ service,
+ cid,
+ port,
+ &mut assigned_port,
+ ))?
+ };
+ Ok((server, assigned_port as _))
}
/// Creates a binder RPC server, serving the supplied binder service implementation on the given
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 49f4cba..495418b 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -52,19 +52,18 @@
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 {
+template <class Mutex>
+class UnlockGuard {
public:
- explicit Deferred(F f) : mF{std::move(f)} {}
+ explicit UnlockGuard(Mutex& lock) : mLock{lock} { mLock.unlock(); }
- ~Deferred() { mF(); }
+ ~UnlockGuard() { mLock.lock(); }
- Deferred(const Deferred&) = delete;
- Deferred& operator=(const Deferred&) = delete;
+ UnlockGuard(const UnlockGuard&) = delete;
+ UnlockGuard& operator=(const UnlockGuard&) = delete;
private:
- F mF;
+ Mutex& mLock;
};
#endif
@@ -271,9 +270,6 @@
void BLASTBufferQueue::onFirstRef() {
// safe default, most producers are expected to override this
mProducer->setMaxDequeuedBufferCount(2);
-#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
- mBufferReleaseThread.emplace(sp<BLASTBufferQueue>::fromExisting(this));
-#endif
}
void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height,
@@ -297,11 +293,11 @@
mSurfaceControl = surface;
SurfaceComposerClient::Transaction t;
if (surfaceControlChanged) {
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+ updateBufferReleaseProducer();
+#endif
t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure,
layer_state_t::eEnableBackpressure);
-#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
- t.setBufferReleaseChannel(mSurfaceControl, mBufferReleaseProducer);
-#endif
applyTransaction = true;
}
mTransformHint = mSurfaceControl->getTransformHint();
@@ -325,7 +321,7 @@
}
if (applyTransaction) {
// All transactions on our apply token are one-way. See comment on mAppliedLastTransaction
- t.setApplyToken(mApplyToken).apply(false, true);
+ t.setApplyToken(mApplyToken).apply(false /* synchronous */, true /* oneWay */);
}
}
@@ -419,7 +415,6 @@
stat.latchTime,
stat.frameEventStats.dequeueReadyTime);
}
-#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
auto currFrameNumber = stat.frameEventStats.frameNumber;
std::vector<ReleaseCallbackId> staleReleases;
for (const auto& [key, value]: mSubmitted) {
@@ -435,7 +430,6 @@
stat.currentMaxAcquiredBufferCount,
true /* fakeRelease */);
}
-#endif
} else {
BQA_LOGE("Failed to find matching SurfaceControl in transactionCallback");
}
@@ -469,6 +463,9 @@
return;
}
bbq->releaseBufferCallback(id, releaseFence, currentMaxAcquiredBufferCount);
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+ bbq->drainBufferReleaseConsumer();
+#endif
};
}
@@ -535,8 +532,6 @@
const sp<Fence>& releaseFence) {
auto it = mSubmitted.find(callbackId);
if (it == mSubmitted.end()) {
- BQA_LOGE("ERROR: releaseBufferCallback without corresponding submitted buffer %s",
- callbackId.to_string().c_str());
return;
}
mNumAcquired--;
@@ -646,12 +641,7 @@
bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform,
bufferItem.mScalingMode, crop);
-#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
- ReleaseBufferCallback releaseBufferCallback =
- applyTransaction ? nullptr : makeReleaseBufferCallbackThunk();
-#else
auto releaseBufferCallback = makeReleaseBufferCallbackThunk();
-#endif
sp<Fence> fence = bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE;
nsecs_t dequeueTime = -1;
@@ -1230,12 +1220,7 @@
// 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--;
- }};
+ UnlockGuard unlockGuard{bufferQueueLock};
ATRACE_FORMAT("waiting for free buffer");
ReleaseCallbackId id;
@@ -1345,6 +1330,35 @@
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+void BLASTBufferQueue::updateBufferReleaseProducer() {
+ // SELinux policy may prevent this process from sending the BufferReleaseChannel's file
+ // descriptor to SurfaceFlinger, causing the entire transaction to be dropped. We send this
+ // transaction independently of any other updates to ensure those updates aren't lost.
+ SurfaceComposerClient::Transaction t;
+ status_t status = t.setApplyToken(mApplyToken)
+ .setBufferReleaseChannel(mSurfaceControl, mBufferReleaseProducer)
+ .apply(false /* synchronous */, true /* oneWay */);
+ if (status != OK) {
+ ALOGW("[%s] %s - failed to set buffer release channel on %s", mName.c_str(),
+ statusToString(status).c_str(), mSurfaceControl->getName().c_str());
+ }
+}
+
+void BLASTBufferQueue::drainBufferReleaseConsumer() {
+ ATRACE_CALL();
+ while (true) {
+ ReleaseCallbackId id;
+ sp<Fence> fence;
+ uint32_t maxAcquiredBufferCount;
+ status_t status =
+ mBufferReleaseConsumer->readReleaseFence(id, fence, maxAcquiredBufferCount);
+ if (status != OK) {
+ return;
+ }
+ releaseBufferCallback(id, fence, maxAcquiredBufferCount);
+ }
+}
+
BLASTBufferQueue::BufferReleaseReader::BufferReleaseReader(BLASTBufferQueue& bbq) : mBbq{bbq} {
mEpollFd = android::base::unique_fd{epoll_create1(EPOLL_CLOEXEC)};
LOG_ALWAYS_FATAL_IF(!mEpollFd.ok(),
@@ -1438,95 +1452,6 @@
}
}
-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 (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() {
- eventfd_write(mEventFd, 1);
-}
-
#endif
} // namespace android
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index e58233c..473a374 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -1556,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;
@@ -1578,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;
}
@@ -1621,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
@@ -1669,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 e9c6ef3..e9cb013 100644
--- a/libs/gui/BufferReleaseChannel.cpp
+++ b/libs/gui/BufferReleaseChannel.cpp
@@ -35,35 +35,35 @@
namespace {
template <typename T>
-static void readAligned(const void*& buffer, size_t& size, T& value) {
+void readAligned(const void*& buffer, size_t& size, T& value) {
size -= FlattenableUtils::align<alignof(T)>(buffer);
FlattenableUtils::read(buffer, size, value);
}
template <typename T>
-static void writeAligned(void*& buffer, size_t& size, T value) {
+void writeAligned(void*& buffer, size_t& size, T value) {
size -= FlattenableUtils::align<alignof(T)>(buffer);
FlattenableUtils::write(buffer, size, value);
}
template <typename T>
-static void addAligned(size_t& size, T /* value */) {
+void addAligned(size_t& size, T /* value */) {
size = FlattenableUtils::align<sizeof(T)>(size);
size += sizeof(T);
}
template <typename T>
-static inline constexpr uint32_t low32(const T n) {
+inline constexpr uint32_t low32(const T n) {
return static_cast<uint32_t>(static_cast<uint64_t>(n));
}
template <typename T>
-static inline constexpr uint32_t high32(const T n) {
+inline constexpr uint32_t high32(const T n) {
return static_cast<uint32_t>(static_cast<uint64_t>(n) >> 32);
}
template <typename T>
-static inline constexpr T to64(const uint32_t lo, const uint32_t hi) {
+inline constexpr T to64(const uint32_t lo, const uint32_t hi) {
return static_cast<T>(static_cast<uint64_t>(hi) << 32 | lo);
}
@@ -139,19 +139,18 @@
std::lock_guard lock{mMutex};
Message message;
mFlattenedBuffer.resize(message.getFlattenedSize());
- std::array<uint8_t, CMSG_SPACE(sizeof(int))> controlMessageBuffer;
+ std::array<uint8_t, CMSG_SPACE(sizeof(int))> controlMessageBuffer{};
iovec iov{
.iov_base = mFlattenedBuffer.data(),
.iov_len = mFlattenedBuffer.size(),
};
- msghdr msg{
- .msg_iov = &iov,
- .msg_iovlen = 1,
- .msg_control = controlMessageBuffer.data(),
- .msg_controllen = controlMessageBuffer.size(),
- };
+ msghdr msg{};
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = controlMessageBuffer.data();
+ msg.msg_controllen = controlMessageBuffer.size();
ssize_t result;
do {
@@ -161,7 +160,7 @@
if (errno == EWOULDBLOCK || errno == EAGAIN) {
return WOULD_BLOCK;
}
- ALOGE("Error reading release fence from socket: error %#x (%s)", errno, strerror(errno));
+ ALOGE("Error reading release fence from socket: error %d (%s)", errno, strerror(errno));
return UNKNOWN_ERROR;
}
@@ -200,9 +199,9 @@
return OK;
}
-int BufferReleaseChannel::ProducerEndpoint::writeReleaseFence(const ReleaseCallbackId& callbackId,
- const sp<Fence>& fence,
- uint32_t maxAcquiredBufferCount) {
+status_t BufferReleaseChannel::ProducerEndpoint::writeReleaseFence(
+ const ReleaseCallbackId& callbackId, const sp<Fence>& fence,
+ uint32_t maxAcquiredBufferCount) {
Message message{callbackId, fence ? fence : Fence::NO_FENCE, maxAcquiredBufferCount};
mFlattenedBuffer.resize(message.getFlattenedSize());
int flattenedFd;
@@ -213,25 +212,22 @@
size_t flattenedBufferSize = mFlattenedBuffer.size();
int* flattenedFdPtr = &flattenedFd;
size_t flattenedFdCount = 1;
- if (status_t err = message.flatten(flattenedBufferPtr, flattenedBufferSize, flattenedFdPtr,
- flattenedFdCount);
- err != OK) {
- ALOGE("Failed to flatten BufferReleaseChannel message.");
- return err;
+ if (status_t status = message.flatten(flattenedBufferPtr, flattenedBufferSize,
+ flattenedFdPtr, flattenedFdCount);
+ status != OK) {
+ return status;
}
}
- iovec iov{
- .iov_base = mFlattenedBuffer.data(),
- .iov_len = mFlattenedBuffer.size(),
- };
+ iovec iov{};
+ iov.iov_base = mFlattenedBuffer.data();
+ iov.iov_len = mFlattenedBuffer.size();
- msghdr msg{
- .msg_iov = &iov,
- .msg_iovlen = 1,
- };
+ msghdr msg{};
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
- std::array<uint8_t, CMSG_SPACE(sizeof(int))> controlMessageBuffer;
+ std::array<uint8_t, CMSG_SPACE(sizeof(int))> controlMessageBuffer{};
if (fence && fence->isValid()) {
msg.msg_control = controlMessageBuffer.data();
msg.msg_controllen = controlMessageBuffer.size();
@@ -248,7 +244,6 @@
result = sendmsg(mFd, &msg, 0);
} while (result == -1 && errno == EINTR);
if (result == -1) {
- ALOGD("Error writing release fence to socket: error %#x (%s)", errno, strerror(errno));
return -errno;
}
@@ -344,13 +339,6 @@
return -errno;
}
- // Make the producer write-only
- if (shutdown(producerFd.get(), SHUT_RD) == -1) {
- ALOGE("[%s] Failed to shutdown reading on producer socket. errno=%d message='%s'",
- name.c_str(), errno, strerror(errno));
- return -errno;
- }
-
outConsumer = std::make_unique<ConsumerEndpoint>(name, std::move(consumerFd));
outProducer = std::make_shared<ProducerEndpoint>(std::move(name), std::move(producerFd));
return STATUS_OK;
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/Surface.cpp b/libs/gui/Surface.cpp
index 66e7ddd..e41f9bb 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -2735,8 +2735,8 @@
bool Surface::waitForNextFrame(uint64_t lastFrame, nsecs_t timeout) {
Mutex::Autolock lock(mMutex);
- if (mNextFrameNumber > lastFrame) {
- return true;
+ if (mLastFrameNumber > lastFrame) {
+ return true;
}
return mQueueBufferCondition.waitRelative(mMutex, timeout) == OK;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index eeea80f..3260c53 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>
@@ -56,6 +57,7 @@
#include <ui/DisplayMode.h>
#include <ui/DisplayState.h>
#include <ui/DynamicDisplayInfo.h>
+#include <ui/FrameRateCategoryRate.h>
#include <android-base/thread_annotations.h>
#include <gui/LayerStatePermissions.h>
@@ -90,6 +92,7 @@
}
constexpr int64_t INVALID_VSYNC = -1;
+const constexpr char* LOG_SURFACE_CONTROL_REGISTRY = "SurfaceControlRegistry";
} // namespace
@@ -871,6 +874,7 @@
const bool earlyWakeupEnd = parcel->readBool();
const int64_t desiredPresentTime = parcel->readInt64();
const bool isAutoTimestamp = parcel->readBool();
+ const bool logCallPoints = parcel->readBool();
FrameTimelineInfo frameTimelineInfo;
frameTimelineInfo.readFromParcel(parcel);
@@ -998,6 +1002,7 @@
parcel->writeBool(mEarlyWakeupEnd);
parcel->writeInt64(mDesiredPresentTime);
parcel->writeBool(mIsAutoTimestamp);
+ parcel->writeBool(mLogCallPoints);
mFrameTimelineInfo.writeToParcel(parcel);
parcel->writeStrongBinder(mApplyToken);
parcel->writeUint32(static_cast<uint32_t>(mDisplayStates.size()));
@@ -1133,6 +1138,12 @@
mergeFrameTimelineInfo(mFrameTimelineInfo, other.mFrameTimelineInfo);
+ mLogCallPoints |= other.mLogCallPoints;
+ if (mLogCallPoints) {
+ ALOG(LOG_DEBUG, LOG_SURFACE_CONTROL_REGISTRY,
+ "Transaction %" PRIu64 " merged with transaction %" PRIu64, other.getId(), mId);
+ }
+
other.clear();
return *this;
}
@@ -1152,6 +1163,7 @@
mFrameTimelineInfo = {};
mApplyToken = nullptr;
mMergedTransactionIds.clear();
+ mLogCallPoints = false;
}
uint64_t SurfaceComposerClient::Transaction::getId() {
@@ -1346,21 +1358,26 @@
sp<IBinder> applyToken = mApplyToken ? mApplyToken : getDefaultApplyToken();
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, flags, applyToken,
- mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp,
- mUncacheBuffers, hasListenerCallbacks, listenerCallbacks, mId,
- mMergedTransactionIds);
+ status_t binderStatus =
+ sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, flags,
+ applyToken, mInputWindowCommands, mDesiredPresentTime,
+ mIsAutoTimestamp, mUncacheBuffers, hasListenerCallbacks,
+ listenerCallbacks, mId, mMergedTransactionIds);
mId = generateId();
// Clear the current states and flags
clear();
- if (synchronous) {
+ if (synchronous && binderStatus == OK) {
syncCallback->wait();
}
+ if (mLogCallPoints) {
+ ALOG(LOG_DEBUG, LOG_SURFACE_CONTROL_REGISTRY, "Transaction %" PRIu64 " applied", mId);
+ }
+
mStatus = NO_ERROR;
- return NO_ERROR;
+ return binderStatus;
}
sp<IBinder> SurfaceComposerClient::Transaction::sApplyToken = new BBinder();
@@ -1374,7 +1391,7 @@
void SurfaceComposerClient::Transaction::setDefaultApplyToken(sp<IBinder> applyToken) {
std::scoped_lock lock{sApplyTokenMutex};
- sApplyToken = applyToken;
+ sApplyToken = std::move(applyToken);
}
status_t SurfaceComposerClient::Transaction::sendSurfaceFlushJankDataTransaction(
@@ -1389,6 +1406,11 @@
t.registerSurfaceControlForCallback(sc);
return t.apply(/*sync=*/false, /* oneWay=*/true);
}
+
+void SurfaceComposerClient::Transaction::enableDebugLogCallPoints() {
+ mLogCallPoints = true;
+}
+
// ---------------------------------------------------------------------------
sp<IBinder> SurfaceComposerClient::createVirtualDisplay(const std::string& displayName,
@@ -1940,15 +1962,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;
}
@@ -2808,6 +2834,8 @@
outInfo->gameContentTypeSupported = ginfo.gameContentTypeSupported;
outInfo->preferredBootDisplayMode = ginfo.preferredBootDisplayMode;
outInfo->hasArrSupport = ginfo.hasArrSupport;
+ outInfo->frameRateCategoryRate = ui::FrameRateCategoryRate(ginfo.frameRateCategoryRate.normal,
+ ginfo.frameRateCategoryRate.high);
}
status_t SurfaceComposerClient::getDynamicDisplayInfoFromId(int64_t displayId,
diff --git a/libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl b/libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl
index 70873b0..67cc273 100644
--- a/libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl
+++ b/libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl
@@ -17,6 +17,7 @@
package android.gui;
import android.gui.DisplayMode;
+import android.gui.FrameRateCategoryRate;
import android.gui.HdrCapabilities;
// Information about a physical display which may change on hotplug reconnect.
@@ -46,4 +47,7 @@
// Represents whether display supports ARR.
boolean hasArrSupport;
+
+ // Represents frame rate for FrameRateCategory Normal and High.
+ FrameRateCategoryRate frameRateCategoryRate;
}
diff --git a/libs/gui/aidl/android/gui/FrameRateCategoryRate.aidl b/libs/gui/aidl/android/gui/FrameRateCategoryRate.aidl
new file mode 100644
index 0000000..f302801
--- /dev/null
+++ b/libs/gui/aidl/android/gui/FrameRateCategoryRate.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+package android.gui;
+
+/** @hide */
+// Represents frame rate for FrameRateCategory Normal and High.
+parcelable FrameRateCategoryRate {
+ float normal;
+ float high;
+}
\ No newline at end of file
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 99c64da..8894b66 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -325,6 +325,14 @@
std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint> mBufferReleaseConsumer;
std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> mBufferReleaseProducer;
+ void updateBufferReleaseProducer() REQUIRES(mMutex);
+ void drainBufferReleaseConsumer();
+
+ // BufferReleaseReader is used to do blocking but interruptible reads from the buffer
+ // release channel. To implement this, BufferReleaseReader owns an epoll file descriptor that
+ // is configured to wake up when either the BufferReleaseReader::ConsumerEndpoint or an eventfd
+ // becomes readable. Interrupts are necessary because a free buffer may become available for
+ // reasons other than a buffer release from the producer.
class BufferReleaseReader {
public:
explicit BufferReleaseReader(BLASTBufferQueue&);
@@ -353,19 +361,6 @@
};
std::optional<BufferReleaseReader> mBufferReleaseReader;
-
- std::atomic<int> mThreadsBlockingOnDequeue = 0;
-
- class BufferReleaseThread {
- public:
- BufferReleaseThread(const sp<BLASTBufferQueue>&);
- ~BufferReleaseThread();
-
- private:
- int mEventFd;
- };
-
- std::optional<BufferReleaseThread> mBufferReleaseThread;
#endif
};
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/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 5ea0c16..e9262b3 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -437,6 +437,8 @@
static void mergeFrameTimelineInfo(FrameTimelineInfo& t, const FrameTimelineInfo& other);
// Tracks registered callbacks
sp<TransactionCompletedListener> mTransactionCompletedListener = nullptr;
+ // Prints debug logs when enabled.
+ bool mLogCallPoints = false;
protected:
std::unordered_map<sp<IBinder>, ComposerState, IBinderHash> mComposerStates;
@@ -809,6 +811,7 @@
static void setDefaultApplyToken(sp<IBinder> applyToken);
static status_t sendSurfaceFlushJankDataTransaction(const sp<SurfaceControl>& sc);
+ void enableDebugLogCallPoints();
};
status_t clearLayerFrameStats(const sp<IBinder>& token) const;
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/BufferReleaseChannel_test.cpp b/libs/gui/tests/BufferReleaseChannel_test.cpp
index 11d122b..74f69e1 100644
--- a/libs/gui/tests/BufferReleaseChannel_test.cpp
+++ b/libs/gui/tests/BufferReleaseChannel_test.cpp
@@ -29,11 +29,11 @@
// Helper function to check if two file descriptors point to the same file.
bool is_same_file(int fd1, int fd2) {
- struct stat stat1;
+ struct stat stat1 {};
if (fstat(fd1, &stat1) != 0) {
return false;
}
- struct stat stat2;
+ struct stat stat2 {};
if (fstat(fd2, &stat2) != 0) {
return false;
}
@@ -42,7 +42,18 @@
} // namespace
-TEST(BufferReleaseChannelTest, MessageFlattenable) {
+class BufferReleaseChannelTest : public testing::Test {
+protected:
+ std::unique_ptr<BufferReleaseChannel::ConsumerEndpoint> mConsumer;
+ std::shared_ptr<BufferReleaseChannel::ProducerEndpoint> mProducer;
+
+ void SetUp() override {
+ ASSERT_EQ(OK,
+ BufferReleaseChannel::open("BufferReleaseChannelTest"s, mConsumer, mProducer));
+ }
+};
+
+TEST_F(BufferReleaseChannelTest, MessageFlattenable) {
ReleaseCallbackId releaseCallbackId{1, 2};
sp<Fence> releaseFence = sp<Fence>::make(memfd_create("fake-fence-fd", 0));
uint32_t maxAcquiredBufferCount = 5;
@@ -92,31 +103,23 @@
// Verify that the BufferReleaseChannel consume returns WOULD_BLOCK when there's no message
// available.
-TEST(BufferReleaseChannelTest, ConsumerEndpointIsNonBlocking) {
- std::unique_ptr<BufferReleaseChannel::ConsumerEndpoint> consumer;
- std::shared_ptr<BufferReleaseChannel::ProducerEndpoint> producer;
- ASSERT_EQ(OK, BufferReleaseChannel::open("test-channel"s, consumer, producer));
-
+TEST_F(BufferReleaseChannelTest, ConsumerEndpointIsNonBlocking) {
ReleaseCallbackId releaseCallbackId;
sp<Fence> releaseFence;
uint32_t maxAcquiredBufferCount;
ASSERT_EQ(WOULD_BLOCK,
- consumer->readReleaseFence(releaseCallbackId, releaseFence, maxAcquiredBufferCount));
+ mConsumer->readReleaseFence(releaseCallbackId, releaseFence, maxAcquiredBufferCount));
}
// Verify that we can write a message to the BufferReleaseChannel producer and read that message
// using the BufferReleaseChannel consumer.
-TEST(BufferReleaseChannelTest, ProduceAndConsume) {
- std::unique_ptr<BufferReleaseChannel::ConsumerEndpoint> consumer;
- std::shared_ptr<BufferReleaseChannel::ProducerEndpoint> producer;
- ASSERT_EQ(OK, BufferReleaseChannel::open("test-channel"s, consumer, producer));
-
+TEST_F(BufferReleaseChannelTest, ProduceAndConsume) {
sp<Fence> fence = sp<Fence>::make(memfd_create("fake-fence-fd", 0));
for (uint64_t i = 0; i < 64; i++) {
ReleaseCallbackId producerId{i, i + 1};
uint32_t maxAcquiredBufferCount = i + 2;
- ASSERT_EQ(OK, producer->writeReleaseFence(producerId, fence, maxAcquiredBufferCount));
+ ASSERT_EQ(OK, mProducer->writeReleaseFence(producerId, fence, maxAcquiredBufferCount));
}
for (uint64_t i = 0; i < 64; i++) {
@@ -127,7 +130,7 @@
sp<Fence> consumerFence;
uint32_t maxAcquiredBufferCount;
ASSERT_EQ(OK,
- consumer->readReleaseFence(consumerId, consumerFence, maxAcquiredBufferCount));
+ mConsumer->readReleaseFence(consumerId, consumerFence, maxAcquiredBufferCount));
ASSERT_EQ(expectedId, consumerId);
ASSERT_TRUE(is_same_file(fence->get(), consumerFence->get()));
@@ -135,4 +138,16 @@
}
}
+// Verify that BufferReleaseChannel::ConsumerEndpoint's socket can't be written to.
+TEST_F(BufferReleaseChannelTest, ConsumerSocketReadOnly) {
+ uint64_t data = 0;
+ ASSERT_EQ(-1, write(mConsumer->getFd().get(), &data, sizeof(uint64_t)));
+ ASSERT_EQ(errno, EPIPE);
+}
+
+// Verify that BufferReleaseChannel::ProducerEndpoint's socket can't be read from.
+TEST_F(BufferReleaseChannelTest, ProducerSocketWriteOnly) {
+ ASSERT_EQ(0, read(mProducer->getFd().get(), nullptr, sizeof(uint64_t)));
+}
+
} // namespace android
\ No newline at end of file
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 7d0b512..17630e3 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -294,7 +294,7 @@
transactionBody) {
SurfaceComposerClient::Transaction t;
transactionBody(t, mSurfaceControl);
- t.apply(true);
+ t.apply(/*synchronously=*/true);
}
virtual void showAt(int x, int y, Rect crop = Rect(0, 0, 100, 100)) {
@@ -307,7 +307,7 @@
t.setAlpha(mSurfaceControl, 1);
auto reportedListener = sp<SynchronousWindowInfosReportedListener>::make();
t.addWindowInfosReportedListener(reportedListener);
- t.apply();
+ t.apply(/*synchronously=*/true);
reportedListener->wait();
}
@@ -319,7 +319,7 @@
request.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
request.displayId = displayId.val();
t.setFocusedWindow(request);
- t.apply(true);
+ t.apply(/*synchronously=*/true);
}
public:
@@ -363,7 +363,7 @@
transactionBody) override {
SurfaceComposerClient::Transaction t;
transactionBody(t, mParentSurfaceControl);
- t.apply(true);
+ t.apply(/*synchronously=*/true);
}
void showAt(int x, int y, Rect crop = Rect(0, 0, 100, 100)) override {
@@ -377,7 +377,7 @@
t.setInputWindowInfo(mSurfaceControl, mInputInfo);
t.setCrop(mSurfaceControl, crop);
t.setAlpha(mSurfaceControl, 1);
- t.apply(true);
+ t.apply(/*synchronously=*/true);
}
private:
@@ -417,7 +417,7 @@
BufferUsage::COMPOSER_OVERLAY | BufferUsage::GPU_TEXTURE;
sp<GraphicBuffer> buffer =
new GraphicBuffer(w, h, PIXEL_FORMAT_RGBA_8888, 1, usageFlags, "test");
- Transaction().setBuffer(layer, buffer).apply(true);
+ Transaction().setBuffer(layer, buffer).apply(/*synchronously=*/true);
usleep(mBufferPostDelay);
}
@@ -1116,6 +1116,8 @@
* in its parent's touchable region. The input events should be in the layer's coordinate space.
*/
TEST_F(InputSurfacesTest, uncropped_container_replaces_touchable_region_with_null_crop) {
+ std::unique_ptr<InputSurface> bgContainer =
+ InputSurface::makeContainerInputSurface(mComposerClient, 0, 0);
std::unique_ptr<InputSurface> parentContainer =
InputSurface::makeContainerInputSurface(mComposerClient, 0, 0);
std::unique_ptr<InputSurface> containerSurface =
@@ -1124,6 +1126,9 @@
[&](auto& t, auto& sc) { t.reparent(sc, parentContainer->mSurfaceControl); });
containerSurface->mInputInfo.replaceTouchableRegionWithCrop = true;
containerSurface->mInputInfo.touchableRegionCropHandle = nullptr;
+ parentContainer->doTransaction(
+ [&](auto& t, auto& sc) { t.reparent(sc, bgContainer->mSurfaceControl); });
+ bgContainer->showAt(0, 0, Rect(0, 0, 100, 100));
parentContainer->showAt(10, 10, Rect(0, 0, 20, 20));
containerSurface->showAt(10, 10, Rect::INVALID_RECT);
@@ -1207,7 +1212,7 @@
t.setDisplayLayerStack(token, layerStack);
t.setDisplayProjection(token, ui::ROTATION_0, {0, 0, width, height},
{offsetX, offsetY, offsetX + width, offsetY + height});
- t.apply(true);
+ t.apply(/*synchronously=*/true);
mVirtualDisplays.push_back(token);
}
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/KeyboardClassifier.cpp b/libs/input/KeyboardClassifier.cpp
index 0c2c7be..2a83919 100644
--- a/libs/input/KeyboardClassifier.cpp
+++ b/libs/input/KeyboardClassifier.cpp
@@ -57,14 +57,14 @@
uint32_t deviceClasses) {
if (mRustClassifier) {
RustInputDeviceIdentifier rustIdentifier;
- rustIdentifier.name = identifier.name;
- rustIdentifier.location = identifier.location;
- rustIdentifier.unique_id = identifier.uniqueId;
+ rustIdentifier.name = rust::String::lossy(identifier.name);
+ rustIdentifier.location = rust::String::lossy(identifier.location);
+ rustIdentifier.unique_id = rust::String::lossy(identifier.uniqueId);
rustIdentifier.bus = identifier.bus;
rustIdentifier.vendor = identifier.vendor;
rustIdentifier.product = identifier.product;
rustIdentifier.version = identifier.version;
- rustIdentifier.descriptor = identifier.descriptor;
+ rustIdentifier.descriptor = rust::String::lossy(identifier.descriptor);
android::input::keyboardClassifier::notifyKeyboardChanged(**mRustClassifier, deviceId,
rustIdentifier, deviceClasses);
} else {
diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig
index 701fb43..fd77048 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,27 @@
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
+ }
+}
+
+flag {
+ name: "connected_displays_cursor"
+ namespace: "lse_desktop_experience"
+ description: "Allow cursor to transition across multiple connected displays"
+ bug: "362719483"
+}
diff --git a/libs/input/tests/TestEventMatchers.h b/libs/input/tests/TestEventMatchers.h
index 3589de5..290a97d 100644
--- a/libs/input/tests/TestEventMatchers.h
+++ b/libs/input/tests/TestEventMatchers.h
@@ -75,12 +75,18 @@
using is_gtest_matcher = void;
explicit WithMotionActionMatcher(int32_t action) : mAction(action) {}
- bool MatchAndExplain(const MotionEvent& event, std::ostream*) const {
- bool matches = mAction == event.getAction();
- if (event.getAction() == AMOTION_EVENT_ACTION_CANCEL) {
- matches &= (event.getFlags() & AMOTION_EVENT_FLAG_CANCELED) != 0;
+ bool MatchAndExplain(const MotionEvent& event, testing::MatchResultListener* listener) const {
+ if (mAction != event.getAction()) {
+ *listener << "expected " << MotionEvent::actionToString(mAction) << ", but got "
+ << MotionEvent::actionToString(event.getAction());
+ return false;
}
- return matches;
+ if (event.getAction() == AMOTION_EVENT_ACTION_CANCEL &&
+ (event.getFlags() & AMOTION_EVENT_FLAG_CANCELED) == 0) {
+ *listener << "event with CANCEL action is missing FLAG_CANCELED";
+ return false;
+ }
+ return true;
}
void DescribeTo(std::ostream* os) const {
diff --git a/libs/input/tests/TfLiteMotionPredictor_test.cpp b/libs/input/tests/TfLiteMotionPredictor_test.cpp
index c3ac0b7..0c19ebe 100644
--- a/libs/input/tests/TfLiteMotionPredictor_test.cpp
+++ b/libs/input/tests/TfLiteMotionPredictor_test.cpp
@@ -89,23 +89,23 @@
buffers.pushSample(/*timestamp=*/1,
{.position = {.x = 10, .y = 10},
.pressure = 0,
- .orientation = 0,
- .tilt = 0.2});
+ .tilt = 0.2,
+ .orientation = 0});
buffers.pushSample(/*timestamp=*/2,
{.position = {.x = 10, .y = 50},
.pressure = 0.4,
- .orientation = M_PI / 4,
- .tilt = 0.3});
+ .tilt = 0.3,
+ .orientation = M_PI / 4});
buffers.pushSample(/*timestamp=*/3,
{.position = {.x = 30, .y = 50},
.pressure = 0.5,
- .orientation = -M_PI / 4,
- .tilt = 0.4});
+ .tilt = 0.4,
+ .orientation = -M_PI / 4});
buffers.pushSample(/*timestamp=*/3,
{.position = {.x = 30, .y = 60},
.pressure = 0,
- .orientation = 0,
- .tilt = 0.5});
+ .tilt = 0.5,
+ .orientation = 0});
buffers.copyTo(*model);
const int zeroPadding = model->inputLength() - 3;
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index f97eed5..ac3a832 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -263,6 +263,16 @@
return native_window_set_frame_rate(window, frameRate, compatibility, changeFrameRateStrategy);
}
+int32_t ANativeWindow_setFrameRateParams(
+ ANativeWindow* window, float desiredMinRate, float desiredMaxRate, float fixedSourceRate,
+ ANativeWindow_ChangeFrameRateStrategy changeFrameRateStrategy) {
+ if (!window || !query(window, NATIVE_WINDOW_IS_VALID)) {
+ return -EINVAL;
+ }
+ return native_window_set_frame_rate_params(window, desiredMinRate, desiredMaxRate,
+ fixedSourceRate, changeFrameRateStrategy);
+}
+
/**************************************************************************************************
* vndk-stable
**************************************************************************************************/
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/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index be6623e..bd8d67a 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -33,8 +33,8 @@
#ifndef ANDROID_NATIVE_WINDOW_H
#define ANDROID_NATIVE_WINDOW_H
-#include <stdint.h>
#include <stdbool.h>
+#include <stdint.h>
#include <sys/cdefs.h>
#include <android/data_space.h>
@@ -282,7 +282,7 @@
void ANativeWindow_tryAllocateBuffers(ANativeWindow* window) __INTRODUCED_IN(30);
/** Change frame rate strategy value for ANativeWindow_setFrameRate. */
-enum ANativeWindow_ChangeFrameRateStrategy {
+typedef enum ANativeWindow_ChangeFrameRateStrategy : int8_t {
/**
* Change the frame rate only if the transition is going to be seamless.
*/
@@ -292,7 +292,7 @@
* i.e. with visual interruptions for the user.
*/
ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS = 1
-} __INTRODUCED_IN(31);
+} ANativeWindow_ChangeFrameRateStrategy __INTRODUCED_IN(31);
/**
* Sets the intended frame rate for this window.
@@ -345,6 +345,76 @@
__INTRODUCED_IN(31);
/**
+ * Sets the intended frame rate for this window.
+ *
+ * On devices that are capable of running the display at different frame rates,
+ * the system may choose a display refresh rate to better match this surface's frame
+ * rate. Usage of this API won't introduce frame rate throttling, or affect other
+ * aspects of the application's frame production pipeline. However, because the system
+ * may change the display refresh rate, calls to this function may result in changes
+ * to Choreographer callback timings, and changes to the time interval at which the
+ * system releases buffers back to the application.
+ *
+ * Note that this only has an effect for surfaces presented on the display. If this
+ * surface is consumed by something other than the system compositor, e.g. a media
+ * codec, this call has no effect.
+ *
+ * You can register for changes in the refresh rate using
+ * \a AChoreographer_registerRefreshRateCallback.
+ *
+ * See ANativeWindow_clearFrameRate().
+ *
+ * Available since API level 36.
+ *
+ * \param window pointer to an ANativeWindow object.
+ *
+ * \param desiredMinRate The desired minimum frame rate (inclusive) for the window, specifying that
+ * the surface prefers the device render rate to be at least `desiredMinRate`.
+ *
+ * <p>Set `desiredMinRate` = `desiredMaxRate` to indicate the surface prefers an exact frame rate.
+ *
+ * <p>Set `desiredMinRate` = 0 to indicate the window has no preference
+ * and any frame rate is acceptable.
+ *
+ * <p>The value should be greater than or equal to 0.
+ *
+ * \param desiredMaxRate The desired maximum frame rate (inclusive) for the window, specifying that
+ * the surface prefers the device render rate to be at most `desiredMaxRate`.
+ *
+ * <p>Set `desiredMaxRate` = `desiredMinRate` to indicate the surface prefers an exact frame rate.
+ *
+ * <p>Set `desiredMaxRate` = positive infinity to indicate the window has no preference
+ * and any frame rate is acceptable.
+ *
+ * <p>The value should be greater than or equal to `desiredMinRate`.
+ *
+ * \param fixedSourceRate The "fixed source" frame rate of the window if the content has an
+ * inherently fixed frame rate, e.g. a video that has a specific frame rate.
+ *
+ * <p>When the frame rate chosen for the surface is the `fixedSourceRate` or a
+ * multiple, the surface can render without frame pulldown, for optimal smoothness. For
+ * example, a 30 fps video (`fixedSourceRate`=30) renders just as smoothly on 30 fps,
+ * 60 fps, 90 fps, 120 fps, and so on.
+ *
+ * <p>Setting the fixed source rate can also be used together with a desired
+ * frame rate min and max via setting `desiredMinRate` and `desiredMaxRate`. This still
+ * means the window's content has a fixed frame rate of `fixedSourceRate`, but additionally
+ * specifies the preference to be in the range [`desiredMinRate`, `desiredMaxRate`]. For example, an
+ * app might want to specify there is 30 fps video (`fixedSourceRate`=30) as well as a smooth
+ * animation on the same window which looks good when drawing within a frame rate range such as
+ * [`desiredMinRate`, `desiredMaxRate`] = [60,120].
+ *
+ * \param changeFrameRateStrategy Whether display refresh rate transitions caused by this surface
+ * should be seamless. A seamless transition is one that doesn't have any visual interruptions, such
+ * as a black screen for a second or two.
+ *
+ * \return 0 for success, -EINVAL if the arguments are invalid.
+ */
+int32_t ANativeWindow_setFrameRateParams(
+ ANativeWindow* window, float desiredMinRate, float desiredMaxRate, float fixedSourceRate,
+ ANativeWindow_ChangeFrameRateStrategy changeFrameRateStrategy) __INTRODUCED_IN(36);
+
+/**
* Clears the frame rate which is set for this window.
*
* This is equivalent to calling
@@ -366,14 +436,13 @@
*
* See ANativeWindow_setFrameRateWithChangeStrategy().
*
- * Available since API level 34.
+ * Available since API level 31.
*
* \param window pointer to an ANativeWindow object.
*
* \return 0 for success, -EINVAL if the window value is invalid.
*/
-inline int32_t ANativeWindow_clearFrameRate(ANativeWindow* window)
- __INTRODUCED_IN(__ANDROID_API_U__) {
+inline int32_t ANativeWindow_clearFrameRate(ANativeWindow* window) __INTRODUCED_IN(31) {
return ANativeWindow_setFrameRateWithChangeStrategy(window, 0,
ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 33c303a..05f49ad 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -1156,6 +1156,23 @@
(int)compatibility, (int)changeFrameRateStrategy);
}
+static inline int native_window_set_frame_rate_params(struct ANativeWindow* window,
+ float desiredMinRate, float desiredMaxRate,
+ float fixedSourceRate,
+ int8_t changeFrameRateStrategy) {
+ // TODO(b/362798998): Fix plumbing to send whole params
+ int compatibility = fixedSourceRate == 0 ? ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT
+ : ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE;
+ double frameRate = compatibility == ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
+ ? fixedSourceRate
+ : desiredMinRate;
+ if (desiredMaxRate < desiredMinRate) {
+ return -EINVAL;
+ }
+ return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, frameRate, compatibility,
+ changeFrameRateStrategy);
+}
+
struct ANativeWindowFrameTimelineInfo {
// Frame Id received from ANativeWindow_getNextFrameId.
uint64_t frameNumber;
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index e29d5a6..071e354 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -53,6 +53,7 @@
ANativeWindow_setBuffersTransform;
ANativeWindow_setDequeueTimeout; # systemapi introduced=30
ANativeWindow_setFrameRate; # introduced=30
+ ANativeWindow_setFrameRateParams; # introduced=36
ANativeWindow_setFrameRateWithChangeStrategy; # introduced=31
ANativeWindow_setSharedBufferMode; # llndk
ANativeWindow_setSwapInterval; # llndk
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..014c912 100644
--- a/libs/nativewindow/rust/src/lib.rs
+++ b/libs/nativewindow/rust/src/lib.rs
@@ -203,8 +203,8 @@
Self(buffer_ptr)
}
- /// Creates a new Rust HardwareBuffer to wrap the given AHardwareBuffer without taking ownership
- /// of it.
+ /// Creates a new Rust HardwareBuffer to wrap the given `AHardwareBuffer` without taking
+ /// ownership of it.
///
/// Unlike [`from_raw`](Self::from_raw) this method will increment the refcount on the buffer.
/// This means that the caller can continue to use the raw buffer it passed in, and must call
@@ -220,8 +220,20 @@
Self(buffer)
}
- /// 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.
+ /// Returns the internal `AHardwareBuffer` pointer.
+ ///
+ /// This is only valid as long as this `HardwareBuffer` exists, so shouldn't be stored. It can
+ /// be used to provide a pointer for a C/C++ API over FFI.
+ pub fn as_raw(&self) -> NonNull<AHardwareBuffer> {
+ self.0
+ }
+
+ /// Gets the internal `AHardwareBuffer` pointer without decrementing the refcount. This can
+ /// be used for a C/C++ API which takes ownership of the pointer.
+ ///
+ /// The caller is responsible for releasing the `AHardwareBuffer` pointer by calling
+ /// `AHardwareBuffer_release` when it is finished with it, or may convert it back to a Rust
+ /// `HardwareBuffer` by calling [`HardwareBuffer::from_raw`].
pub fn into_raw(self) -> NonNull<AHardwareBuffer> {
let buffer = ManuallyDrop::new(self);
buffer.0
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/libs/renderengine/skia/GaneshVkRenderEngine.cpp b/libs/renderengine/skia/GaneshVkRenderEngine.cpp
index a3a43e2..cc73f40 100644
--- a/libs/renderengine/skia/GaneshVkRenderEngine.cpp
+++ b/libs/renderengine/skia/GaneshVkRenderEngine.cpp
@@ -21,12 +21,15 @@
#include <include/gpu/ganesh/vk/GrVkBackendSemaphore.h>
+#include <android-base/stringprintf.h>
#include <common/trace.h>
#include <log/log_main.h>
#include <sync/sync.h>
namespace android::renderengine::skia {
+using base::StringAppendF;
+
std::unique_ptr<GaneshVkRenderEngine> GaneshVkRenderEngine::create(
const RenderEngineCreationArgs& args) {
std::unique_ptr<GaneshVkRenderEngine> engine(new GaneshVkRenderEngine(args));
@@ -111,4 +114,9 @@
return res;
}
+void GaneshVkRenderEngine::appendBackendSpecificInfoToDump(std::string& result) {
+ StringAppendF(&result, "\n ------------RE Vulkan (Ganesh)----------\n");
+ SkiaVkRenderEngine::appendBackendSpecificInfoToDump(result);
+}
+
} // namespace android::renderengine::skia
diff --git a/libs/renderengine/skia/GaneshVkRenderEngine.h b/libs/renderengine/skia/GaneshVkRenderEngine.h
index e6123c2..ba17f71 100644
--- a/libs/renderengine/skia/GaneshVkRenderEngine.h
+++ b/libs/renderengine/skia/GaneshVkRenderEngine.h
@@ -28,6 +28,7 @@
std::unique_ptr<SkiaGpuContext> createContext(VulkanInterface& vulkanInterface) override;
void waitFence(SkiaGpuContext* context, base::borrowed_fd fenceFd) override;
base::unique_fd flushAndSubmit(SkiaGpuContext* context, sk_sp<SkSurface> dstSurface) override;
+ void appendBackendSpecificInfoToDump(std::string& result) override;
private:
GaneshVkRenderEngine(const RenderEngineCreationArgs& args) : SkiaVkRenderEngine(args) {}
diff --git a/libs/renderengine/skia/GraphiteVkRenderEngine.cpp b/libs/renderengine/skia/GraphiteVkRenderEngine.cpp
index 390ad6e..a9332fa 100644
--- a/libs/renderengine/skia/GraphiteVkRenderEngine.cpp
+++ b/libs/renderengine/skia/GraphiteVkRenderEngine.cpp
@@ -25,6 +25,7 @@
#include <include/gpu/graphite/Recording.h>
#include <include/gpu/graphite/vk/VulkanGraphiteTypes.h>
+#include <android-base/stringprintf.h>
#include <log/log_main.h>
#include <sync/sync.h>
@@ -33,6 +34,8 @@
namespace android::renderengine::skia {
+using base::StringAppendF;
+
std::unique_ptr<GraphiteVkRenderEngine> GraphiteVkRenderEngine::create(
const RenderEngineCreationArgs& args) {
std::unique_ptr<GraphiteVkRenderEngine> engine(new GraphiteVkRenderEngine(args));
@@ -139,4 +142,9 @@
return drawFenceFd;
}
+void GraphiteVkRenderEngine::appendBackendSpecificInfoToDump(std::string& result) {
+ StringAppendF(&result, "\n ------------RE Vulkan (Graphite)----------\n");
+ SkiaVkRenderEngine::appendBackendSpecificInfoToDump(result);
+}
+
} // namespace android::renderengine::skia
diff --git a/libs/renderengine/skia/GraphiteVkRenderEngine.h b/libs/renderengine/skia/GraphiteVkRenderEngine.h
index cf24a3b..33a47f1 100644
--- a/libs/renderengine/skia/GraphiteVkRenderEngine.h
+++ b/libs/renderengine/skia/GraphiteVkRenderEngine.h
@@ -30,6 +30,7 @@
std::unique_ptr<SkiaGpuContext> createContext(VulkanInterface& vulkanInterface) override;
void waitFence(SkiaGpuContext* context, base::borrowed_fd fenceFd) override;
base::unique_fd flushAndSubmit(SkiaGpuContext* context, sk_sp<SkSurface> dstSurface) override;
+ void appendBackendSpecificInfoToDump(std::string& result) override;
private:
GraphiteVkRenderEngine(const RenderEngineCreationArgs& args) : SkiaVkRenderEngine(args) {}
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 4ef7d5b..ddae9fc 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -541,7 +541,7 @@
void SkiaGLRenderEngine::appendBackendSpecificInfoToDump(std::string& result) {
const GLExtensions& extensions = GLExtensions::getInstance();
- StringAppendF(&result, "\n ------------RE GLES------------\n");
+ StringAppendF(&result, "\n ------------RE GLES (Ganesh)------------\n");
StringAppendF(&result, "EGL implementation : %s\n", extensions.getEGLVersion());
StringAppendF(&result, "%s\n", extensions.getEGLExtensions());
StringAppendF(&result, "GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(),
diff --git a/libs/renderengine/skia/SkiaVkRenderEngine.cpp b/libs/renderengine/skia/SkiaVkRenderEngine.cpp
index 677a2b6..177abe6 100644
--- a/libs/renderengine/skia/SkiaVkRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaVkRenderEngine.cpp
@@ -169,24 +169,26 @@
}
void SkiaVkRenderEngine::appendBackendSpecificInfoToDump(std::string& result) {
- StringAppendF(&result, "\n ------------RE Vulkan----------\n");
- StringAppendF(&result, "\n Vulkan device initialized: %d\n", sVulkanInterface.isInitialized());
- StringAppendF(&result, "\n Vulkan protected device initialized: %d\n",
+ // Subclasses will prepend a backend-specific name / section header
+ StringAppendF(&result, "Vulkan device initialized: %d\n", sVulkanInterface.isInitialized());
+ StringAppendF(&result, "Vulkan protected device initialized: %d\n",
sProtectedContentVulkanInterface.isInitialized());
if (!sVulkanInterface.isInitialized()) {
return;
}
- StringAppendF(&result, "\n Instance extensions:\n");
+ StringAppendF(&result, "Instance extensions: [\n");
for (const auto& name : sVulkanInterface.getInstanceExtensionNames()) {
- StringAppendF(&result, "\n %s\n", name.c_str());
+ StringAppendF(&result, " %s\n", name.c_str());
}
+ StringAppendF(&result, "]\n");
- StringAppendF(&result, "\n Device extensions:\n");
+ StringAppendF(&result, "Device extensions: [\n");
for (const auto& name : sVulkanInterface.getDeviceExtensionNames()) {
- StringAppendF(&result, "\n %s\n", name.c_str());
+ StringAppendF(&result, " %s\n", name.c_str());
}
+ StringAppendF(&result, "]\n");
}
} // namespace skia
diff --git a/libs/renderengine/skia/SkiaVkRenderEngine.h b/libs/renderengine/skia/SkiaVkRenderEngine.h
index d2bb3d5..88b04df 100644
--- a/libs/renderengine/skia/SkiaVkRenderEngine.h
+++ b/libs/renderengine/skia/SkiaVkRenderEngine.h
@@ -81,7 +81,7 @@
SkiaRenderEngine::Contexts createContexts() override;
bool supportsProtectedContentImpl() const override;
bool useProtectedContextImpl(GrProtected isProtected) override;
- void appendBackendSpecificInfoToDump(std::string& result) override;
+ virtual void appendBackendSpecificInfoToDump(std::string& result) override;
// TODO: b/300533018 - refactor this to be non-static
static VulkanInterface& getVulkanInterface(bool protectedContext);
diff --git a/libs/tracing_perfetto/Android.bp b/libs/tracing_perfetto/Android.bp
index b5c56c5..9a2d4f7 100644
--- a/libs/tracing_perfetto/Android.bp
+++ b/libs/tracing_perfetto/Android.bp
@@ -47,4 +47,6 @@
],
host_supported: true,
+ // for vndbinder
+ vendor_available: true,
}
diff --git a/libs/tracing_perfetto/tracing_perfetto_internal.cpp b/libs/tracing_perfetto/tracing_perfetto_internal.cpp
index 9a0042a..c4f8663 100644
--- a/libs/tracing_perfetto/tracing_perfetto_internal.cpp
+++ b/libs/tracing_perfetto/tracing_perfetto_internal.cpp
@@ -253,15 +253,31 @@
void perfettoTraceAsyncBeginForTrack(const struct PerfettoTeCategory& category, const char* name,
const char* trackName, uint64_t cookie) {
PERFETTO_TE(
- category, PERFETTO_TE_SLICE_BEGIN(name),
- PERFETTO_TE_NAMED_TRACK(trackName, cookie, PerfettoTeProcessTrackUuid()));
+ category, PERFETTO_TE_SLICE_BEGIN(name),
+ PERFETTO_TE_PROTO_TRACK(
+ PerfettoTeNamedTrackUuid(trackName, cookie,
+ PerfettoTeProcessTrackUuid()),
+ PERFETTO_TE_PROTO_FIELD_CSTR(
+ perfetto_protos_TrackDescriptor_atrace_name_field_number,
+ trackName),
+ PERFETTO_TE_PROTO_FIELD_VARINT(
+ perfetto_protos_TrackDescriptor_parent_uuid_field_number,
+ PerfettoTeProcessTrackUuid())));
}
void perfettoTraceAsyncEndForTrack(const struct PerfettoTeCategory& category,
const char* trackName, uint64_t cookie) {
- PERFETTO_TE(
- category, PERFETTO_TE_SLICE_END(),
- PERFETTO_TE_NAMED_TRACK(trackName, cookie, PerfettoTeProcessTrackUuid()));
+ PERFETTO_TE(
+ category, PERFETTO_TE_SLICE_END(),
+ PERFETTO_TE_PROTO_TRACK(
+ PerfettoTeNamedTrackUuid(trackName, cookie,
+ PerfettoTeProcessTrackUuid()),
+ PERFETTO_TE_PROTO_FIELD_CSTR(
+ perfetto_protos_TrackDescriptor_atrace_name_field_number,
+ trackName),
+ PERFETTO_TE_PROTO_FIELD_VARINT(
+ perfetto_protos_TrackDescriptor_parent_uuid_field_number,
+ PerfettoTeProcessTrackUuid())));
}
void perfettoTraceAsyncBegin(const struct PerfettoTeCategory& category, const char* name,
@@ -281,14 +297,35 @@
void perfettoTraceInstantForTrack(const struct PerfettoTeCategory& category,
const char* trackName, const char* name) {
PERFETTO_TE(
- category, PERFETTO_TE_INSTANT(name),
- PERFETTO_TE_NAMED_TRACK(trackName, 1, PerfettoTeProcessTrackUuid()));
+ category, PERFETTO_TE_INSTANT(name),
+ PERFETTO_TE_PROTO_TRACK(
+ PerfettoTeNamedTrackUuid(trackName, 1,
+ PerfettoTeProcessTrackUuid()),
+ PERFETTO_TE_PROTO_FIELD_CSTR(
+ perfetto_protos_TrackDescriptor_atrace_name_field_number,
+ trackName),
+ PERFETTO_TE_PROTO_FIELD_VARINT(
+ perfetto_protos_TrackDescriptor_parent_uuid_field_number,
+ PerfettoTeProcessTrackUuid())));
}
void perfettoTraceCounter(const struct PerfettoTeCategory& category,
- [[maybe_unused]] const char* name, int64_t value) {
- PERFETTO_TE(category, PERFETTO_TE_COUNTER(),
- PERFETTO_TE_INT_COUNTER(value));
+ const char* name, int64_t value) {
+ PERFETTO_TE(
+ category, PERFETTO_TE_COUNTER(),
+ PERFETTO_TE_PROTO_TRACK(
+ PerfettoTeCounterTrackUuid(name,
+ PerfettoTeProcessTrackUuid()),
+ PERFETTO_TE_PROTO_FIELD_CSTR(
+ perfetto_protos_TrackDescriptor_atrace_name_field_number,
+ name),
+ PERFETTO_TE_PROTO_FIELD_VARINT(
+ perfetto_protos_TrackDescriptor_parent_uuid_field_number,
+ PerfettoTeProcessTrackUuid()),
+ PERFETTO_TE_PROTO_FIELD_BYTES(
+ perfetto_protos_TrackDescriptor_counter_field_number,
+ PERFETTO_NULL, 0)),
+ PERFETTO_TE_INT_COUNTER(value));
}
} // namespace internal
diff --git a/libs/ui/include/ui/DynamicDisplayInfo.h b/libs/ui/include/ui/DynamicDisplayInfo.h
index 25a2b6e..af494dc 100644
--- a/libs/ui/include/ui/DynamicDisplayInfo.h
+++ b/libs/ui/include/ui/DynamicDisplayInfo.h
@@ -22,6 +22,7 @@
#include <optional>
#include <vector>
+#include <ui/FrameRateCategoryRate.h>
#include <ui/GraphicTypes.h>
#include <ui/HdrCapabilities.h>
@@ -55,6 +56,9 @@
std::optional<ui::DisplayMode> getActiveDisplayMode() const;
bool hasArrSupport;
+
+ // Represents frame rate for FrameRateCategory Normal and High.
+ ui::FrameRateCategoryRate frameRateCategoryRate;
};
} // namespace android::ui
diff --git a/libs/ui/include/ui/FrameRateCategoryRate.h b/libs/ui/include/ui/FrameRateCategoryRate.h
new file mode 100644
index 0000000..9c392d9
--- /dev/null
+++ b/libs/ui/include/ui/FrameRateCategoryRate.h
@@ -0,0 +1,35 @@
+/*
+ * 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
+
+namespace android::ui {
+
+// Represents frame rate for FrameRateCategory Normal and High.
+class FrameRateCategoryRate {
+public:
+ FrameRateCategoryRate(float normal = 0, float high = 0) : mNormal(normal), mHigh(high) {}
+
+ float getNormal() const { return mNormal; }
+
+ float getHigh() const { return mHigh; }
+
+private:
+ float mNormal;
+ float mHigh;
+};
+
+} // namespace android::ui
\ No newline at end of file
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/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 4f9d9e4..755995c 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -836,13 +836,9 @@
}
Result<void> validateWindowInfosUpdate(const gui::WindowInfosUpdate& update) {
- struct HashFunction {
- size_t operator()(const WindowInfo& info) const { return info.id; }
- };
-
- std::unordered_set<WindowInfo, HashFunction> windowSet;
+ std::unordered_set<int32_t> windowIds;
for (const WindowInfo& info : update.windowInfos) {
- const auto [_, inserted] = windowSet.insert(info);
+ const auto [_, inserted] = windowIds.insert(info.id);
if (!inserted) {
return Error() << "Duplicate entry for " << info;
}
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index 756a29b..305feab 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.
@@ -243,6 +242,9 @@
// context (a.k.a. "right") clicks.
bool touchpadRightClickZoneEnabled;
+ // True to use three-finger tap as a customizable shortcut; false to use it as a middle-click.
+ bool touchpadThreeFingerTapShortcutEnabled;
+
// The set of currently disabled input devices.
std::set<int32_t> disabledDevices;
@@ -294,6 +296,7 @@
touchpadTapDraggingEnabled(false),
shouldNotifyTouchpadHardwareState(false),
touchpadRightClickZoneEnabled(false),
+ touchpadThreeFingerTapShortcutEnabled(false),
stylusButtonMotionEventsEnabled(true),
stylusPointerIconEnabled(false),
mouseReverseVerticalScrollingEnabled(false),
@@ -426,6 +429,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 ---
@@ -487,6 +500,9 @@
/* Sends the Info of gestures that happen on the touchpad. */
virtual void notifyTouchpadGestureInfo(GestureType type, int32_t deviceId) = 0;
+ /* Notifies the policy that the user has performed a three-finger touchpad tap. */
+ virtual void notifyTouchpadThreeFingerTap() = 0;
+
/* Gets the keyboard layout for a particular input device. */
virtual std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay(
const InputDeviceIdentifier& identifier,
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 585f61a..fe3e4c2 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -243,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;
}
@@ -339,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;
}
@@ -502,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/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
index 9a36bfb..ca8266b 100644
--- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
@@ -375,6 +375,9 @@
mPropertyProvider.getProperty("Button Right Click Zone Enable")
.setBoolValues({config.touchpadRightClickZoneEnabled});
mTouchpadHardwareStateNotificationsEnabled = config.shouldNotifyTouchpadHardwareState;
+
+ mGestureConverter.setThreeFingerTapShortcutEnabled(
+ config.touchpadThreeFingerTapShortcutEnabled);
}
std::list<NotifyArgs> out;
if ((!changes.any() && config.pointerCaptureRequest.isEnable()) ||
diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
index da2c683..1959423 100644
--- a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
@@ -261,6 +261,14 @@
}
const uint32_t buttonsPressed = gesture.details.buttons.down;
+ const uint32_t buttonsReleased = gesture.details.buttons.up;
+
+ if (mThreeFingerTapShortcutEnabled && gesture.details.buttons.is_tap &&
+ buttonsPressed == GESTURES_BUTTON_MIDDLE && buttonsReleased == GESTURES_BUTTON_MIDDLE) {
+ mReaderContext.getPolicy()->notifyTouchpadThreeFingerTap();
+ return out;
+ }
+
bool pointerDown = isPointerDown(mButtonState) ||
buttonsPressed &
(GESTURES_BUTTON_LEFT | GESTURES_BUTTON_MIDDLE | GESTURES_BUTTON_RIGHT);
@@ -291,7 +299,6 @@
// changes: a set of buttons going down, followed by a set of buttons going up.
mButtonState = newButtonState;
- const uint32_t buttonsReleased = gesture.details.buttons.up;
for (uint32_t button = 1; button <= GESTURES_BUTTON_FORWARD; button <<= 1) {
if (buttonsReleased & button) {
uint32_t actionButton = gesturesButtonToMotionEventButton(button);
diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.h b/services/inputflinger/reader/mapper/gestures/GestureConverter.h
index c9a35c1..ad40721 100644
--- a/services/inputflinger/reader/mapper/gestures/GestureConverter.h
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.h
@@ -55,6 +55,10 @@
void setBoundsInLogicalDisplay(FloatRect bounds) { mBoundsInLogicalDisplay = bounds; }
+ void setThreeFingerTapShortcutEnabled(bool enabled) {
+ mThreeFingerTapShortcutEnabled = enabled;
+ }
+
void populateMotionRanges(InputDeviceInfo& info) const;
[[nodiscard]] std::list<NotifyArgs> handleGesture(nsecs_t when, nsecs_t readTime,
@@ -101,6 +105,8 @@
const bool mEnableFlingStop;
const bool mEnableNoFocusChange;
+ bool mThreeFingerTapShortcutEnabled;
+
std::optional<ui::LogicalDisplayId> mDisplayId;
FloatRect mBoundsInLogicalDisplay{};
ui::Rotation mOrientation = ui::ROTATION_0;
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 744cf4a..600ae52 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -78,6 +78,7 @@
"PreferStylusOverTouch_test.cpp",
"PropertyProvider_test.cpp",
"RotaryEncoderInputMapper_test.cpp",
+ "SensorInputMapper_test.cpp",
"SlopController_test.cpp",
"SwitchInputMapper_test.cpp",
"SyncQueue_test.cpp",
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..67b1e8c 100644
--- a/services/inputflinger/tests/FakeInputReaderPolicy.cpp
+++ b/services/inputflinger/tests/FakeInputReaderPolicy.cpp
@@ -80,6 +80,17 @@
ASSERT_TRUE(success) << "Timed out waiting for hardware state to be notified";
}
+void FakeInputReaderPolicy::assertTouchpadThreeFingerTapNotified() {
+ std::unique_lock lock(mLock);
+ base::ScopedLockAssertion assumeLocked(mLock);
+
+ const bool success =
+ mTouchpadThreeFingerTapNotified.wait_for(lock, WAIT_TIMEOUT, [this]() REQUIRES(mLock) {
+ return mTouchpadThreeFingerTapHasBeenReported;
+ });
+ ASSERT_TRUE(success) << "Timed out waiting for three-finger tap to be notified";
+}
+
void FakeInputReaderPolicy::clearViewports() {
mViewports.clear();
mConfig.setDisplayViewports(mViewports);
@@ -217,7 +228,6 @@
}
void FakeInputReaderPolicy::setVelocityControlParams(const VelocityControlParameters& params) {
- mConfig.pointerVelocityControlParameters = params;
mConfig.wheelVelocityControlParameters = params;
}
@@ -260,6 +270,12 @@
std::scoped_lock lock(mLock);
}
+void FakeInputReaderPolicy::notifyTouchpadThreeFingerTap() {
+ std::scoped_lock lock(mLock);
+ mTouchpadThreeFingerTapHasBeenReported = true;
+ mTouchpadThreeFingerTapNotified.notify_all();
+}
+
std::shared_ptr<KeyCharacterMap> FakeInputReaderPolicy::getKeyboardLayoutOverlay(
const InputDeviceIdentifier&, const std::optional<KeyboardLayoutInfo>) {
return nullptr;
diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.h b/services/inputflinger/tests/FakeInputReaderPolicy.h
index 3a2b4e9..42c9567 100644
--- a/services/inputflinger/tests/FakeInputReaderPolicy.h
+++ b/services/inputflinger/tests/FakeInputReaderPolicy.h
@@ -43,6 +43,7 @@
void assertStylusGestureNotified(int32_t deviceId);
void assertStylusGestureNotNotified();
void assertTouchpadHardwareStateNotified();
+ void assertTouchpadThreeFingerTapNotified();
virtual void clearViewports();
std::optional<DisplayViewport> getDisplayViewportByUniqueId(const std::string& uniqueId) const;
@@ -86,6 +87,7 @@
void notifyTouchpadHardwareState(const SelfContainedHardwareState& schs,
int32_t deviceId) override;
void notifyTouchpadGestureInfo(GestureType type, int32_t deviceId) override;
+ void notifyTouchpadThreeFingerTap() override;
std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay(
const InputDeviceIdentifier&, const std::optional<KeyboardLayoutInfo>) override;
std::string getDeviceAlias(const InputDeviceIdentifier&) override;
@@ -109,6 +111,9 @@
std::condition_variable mTouchpadHardwareStateNotified;
std::optional<SelfContainedHardwareState> mTouchpadHardwareState GUARDED_BY(mLock){};
+ std::condition_variable mTouchpadThreeFingerTapNotified;
+ bool mTouchpadThreeFingerTapHasBeenReported{false};
+
uint32_t mNextPointerCaptureSequenceNumber{0};
};
diff --git a/services/inputflinger/tests/GestureConverter_test.cpp b/services/inputflinger/tests/GestureConverter_test.cpp
index 225ae0f..fad8f05 100644
--- a/services/inputflinger/tests/GestureConverter_test.cpp
+++ b/services/inputflinger/tests/GestureConverter_test.cpp
@@ -1272,6 +1272,27 @@
WithDisplayId(ui::LogicalDisplayId::DEFAULT)))));
}
+TEST_F(GestureConverterTest, ThreeFingerTap_TriggersShortcut) {
+ InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
+ GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
+ converter.setDisplayId(ui::LogicalDisplayId::DEFAULT);
+ converter.setThreeFingerTapShortcutEnabled(true);
+
+ Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*vx=*/0,
+ /*vy=*/0, GESTURES_FLING_TAP_DOWN);
+ std::list<NotifyArgs> args =
+ converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, flingGesture);
+ // We don't need to check args here, since it's covered by the FlingTapDown test.
+
+ Gesture tapGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
+ /*down=*/GESTURES_BUTTON_MIDDLE, /*up=*/GESTURES_BUTTON_MIDDLE,
+ /*is_tap=*/true);
+ args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, tapGesture);
+
+ ASSERT_TRUE(args.empty());
+ mFakePolicy->assertTouchpadThreeFingerTapNotified();
+}
+
TEST_F(GestureConverterTest, Click) {
// Click should produce button press/release events
InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 6c8b65c..ee3b2a2 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -28,7 +28,6 @@
#include <MultiTouchInputMapper.h>
#include <NotifyArgsBuilders.h>
#include <PeripheralController.h>
-#include <SensorInputMapper.h>
#include <SingleTouchInputMapper.h>
#include <TestEventMatchers.h>
#include <TestInputListener.h>
@@ -36,6 +35,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 +1392,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.
@@ -3017,159 +3031,6 @@
mapper.assertProcessWasCalled();
}
-// --- SensorInputMapperTest ---
-
-class SensorInputMapperTest : public InputMapperTest {
-protected:
- static const int32_t ACCEL_RAW_MIN;
- static const int32_t ACCEL_RAW_MAX;
- static const int32_t ACCEL_RAW_FUZZ;
- static const int32_t ACCEL_RAW_FLAT;
- static const int32_t ACCEL_RAW_RESOLUTION;
-
- static const int32_t GYRO_RAW_MIN;
- static const int32_t GYRO_RAW_MAX;
- static const int32_t GYRO_RAW_FUZZ;
- static const int32_t GYRO_RAW_FLAT;
- static const int32_t GYRO_RAW_RESOLUTION;
-
- static const float GRAVITY_MS2_UNIT;
- static const float DEGREE_RADIAN_UNIT;
-
- void prepareAccelAxes();
- void prepareGyroAxes();
- void setAccelProperties();
- void setGyroProperties();
- void SetUp() override { InputMapperTest::SetUp(DEVICE_CLASSES | InputDeviceClass::SENSOR); }
-};
-
-const int32_t SensorInputMapperTest::ACCEL_RAW_MIN = -32768;
-const int32_t SensorInputMapperTest::ACCEL_RAW_MAX = 32768;
-const int32_t SensorInputMapperTest::ACCEL_RAW_FUZZ = 16;
-const int32_t SensorInputMapperTest::ACCEL_RAW_FLAT = 0;
-const int32_t SensorInputMapperTest::ACCEL_RAW_RESOLUTION = 8192;
-
-const int32_t SensorInputMapperTest::GYRO_RAW_MIN = -2097152;
-const int32_t SensorInputMapperTest::GYRO_RAW_MAX = 2097152;
-const int32_t SensorInputMapperTest::GYRO_RAW_FUZZ = 16;
-const int32_t SensorInputMapperTest::GYRO_RAW_FLAT = 0;
-const int32_t SensorInputMapperTest::GYRO_RAW_RESOLUTION = 1024;
-
-const float SensorInputMapperTest::GRAVITY_MS2_UNIT = 9.80665f;
-const float SensorInputMapperTest::DEGREE_RADIAN_UNIT = 0.0174533f;
-
-void SensorInputMapperTest::prepareAccelAxes() {
- mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_X, ACCEL_RAW_MIN, ACCEL_RAW_MAX, ACCEL_RAW_FUZZ,
- ACCEL_RAW_FLAT, ACCEL_RAW_RESOLUTION);
- mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_Y, ACCEL_RAW_MIN, ACCEL_RAW_MAX, ACCEL_RAW_FUZZ,
- ACCEL_RAW_FLAT, ACCEL_RAW_RESOLUTION);
- mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_Z, ACCEL_RAW_MIN, ACCEL_RAW_MAX, ACCEL_RAW_FUZZ,
- ACCEL_RAW_FLAT, ACCEL_RAW_RESOLUTION);
-}
-
-void SensorInputMapperTest::prepareGyroAxes() {
- mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_RX, GYRO_RAW_MIN, GYRO_RAW_MAX, GYRO_RAW_FUZZ,
- GYRO_RAW_FLAT, GYRO_RAW_RESOLUTION);
- mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_RY, GYRO_RAW_MIN, GYRO_RAW_MAX, GYRO_RAW_FUZZ,
- GYRO_RAW_FLAT, GYRO_RAW_RESOLUTION);
- mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_RZ, GYRO_RAW_MIN, GYRO_RAW_MAX, GYRO_RAW_FUZZ,
- GYRO_RAW_FLAT, GYRO_RAW_RESOLUTION);
-}
-
-void SensorInputMapperTest::setAccelProperties() {
- mFakeEventHub->addSensorAxis(EVENTHUB_ID, /* absCode */ 0, InputDeviceSensorType::ACCELEROMETER,
- /* sensorDataIndex */ 0);
- mFakeEventHub->addSensorAxis(EVENTHUB_ID, /* absCode */ 1, InputDeviceSensorType::ACCELEROMETER,
- /* sensorDataIndex */ 1);
- mFakeEventHub->addSensorAxis(EVENTHUB_ID, /* absCode */ 2, InputDeviceSensorType::ACCELEROMETER,
- /* sensorDataIndex */ 2);
- mFakeEventHub->setMscEvent(EVENTHUB_ID, MSC_TIMESTAMP);
- addConfigurationProperty("sensor.accelerometer.reportingMode", "0");
- addConfigurationProperty("sensor.accelerometer.maxDelay", "100000");
- addConfigurationProperty("sensor.accelerometer.minDelay", "5000");
- addConfigurationProperty("sensor.accelerometer.power", "1.5");
-}
-
-void SensorInputMapperTest::setGyroProperties() {
- mFakeEventHub->addSensorAxis(EVENTHUB_ID, /* absCode */ 3, InputDeviceSensorType::GYROSCOPE,
- /* sensorDataIndex */ 0);
- mFakeEventHub->addSensorAxis(EVENTHUB_ID, /* absCode */ 4, InputDeviceSensorType::GYROSCOPE,
- /* sensorDataIndex */ 1);
- mFakeEventHub->addSensorAxis(EVENTHUB_ID, /* absCode */ 5, InputDeviceSensorType::GYROSCOPE,
- /* sensorDataIndex */ 2);
- mFakeEventHub->setMscEvent(EVENTHUB_ID, MSC_TIMESTAMP);
- addConfigurationProperty("sensor.gyroscope.reportingMode", "0");
- addConfigurationProperty("sensor.gyroscope.maxDelay", "100000");
- addConfigurationProperty("sensor.gyroscope.minDelay", "5000");
- addConfigurationProperty("sensor.gyroscope.power", "0.8");
-}
-
-TEST_F(SensorInputMapperTest, GetSources) {
- SensorInputMapper& mapper = constructAndAddMapper<SensorInputMapper>();
-
- ASSERT_EQ(static_cast<uint32_t>(AINPUT_SOURCE_SENSOR), mapper.getSources());
-}
-
-TEST_F(SensorInputMapperTest, ProcessAccelerometerSensor) {
- setAccelProperties();
- prepareAccelAxes();
- SensorInputMapper& mapper = constructAndAddMapper<SensorInputMapper>();
-
- ASSERT_TRUE(mapper.enableSensor(InputDeviceSensorType::ACCELEROMETER,
- std::chrono::microseconds(10000),
- std::chrono::microseconds(0)));
- ASSERT_TRUE(mFakeEventHub->isDeviceEnabled(EVENTHUB_ID));
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_X, 20000);
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_Y, -20000);
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_Z, 40000);
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_MSC, MSC_TIMESTAMP, 1000);
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
-
- NotifySensorArgs args;
- std::vector<float> values = {20000.0f / ACCEL_RAW_RESOLUTION * GRAVITY_MS2_UNIT,
- -20000.0f / ACCEL_RAW_RESOLUTION * GRAVITY_MS2_UNIT,
- 40000.0f / ACCEL_RAW_RESOLUTION * GRAVITY_MS2_UNIT};
-
- ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifySensorWasCalled(&args));
- ASSERT_EQ(args.source, AINPUT_SOURCE_SENSOR);
- ASSERT_EQ(args.deviceId, DEVICE_ID);
- ASSERT_EQ(args.sensorType, InputDeviceSensorType::ACCELEROMETER);
- ASSERT_EQ(args.accuracy, InputDeviceSensorAccuracy::ACCURACY_HIGH);
- ASSERT_EQ(args.hwTimestamp, ARBITRARY_TIME);
- ASSERT_EQ(args.values, values);
- mapper.flushSensor(InputDeviceSensorType::ACCELEROMETER);
-}
-
-TEST_F(SensorInputMapperTest, ProcessGyroscopeSensor) {
- setGyroProperties();
- prepareGyroAxes();
- SensorInputMapper& mapper = constructAndAddMapper<SensorInputMapper>();
-
- ASSERT_TRUE(mapper.enableSensor(InputDeviceSensorType::GYROSCOPE,
- std::chrono::microseconds(10000),
- std::chrono::microseconds(0)));
- ASSERT_TRUE(mFakeEventHub->isDeviceEnabled(EVENTHUB_ID));
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_RX, 20000);
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_RY, -20000);
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_RZ, 40000);
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_MSC, MSC_TIMESTAMP, 1000);
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
-
- NotifySensorArgs args;
- std::vector<float> values = {20000.0f / GYRO_RAW_RESOLUTION * DEGREE_RADIAN_UNIT,
- -20000.0f / GYRO_RAW_RESOLUTION * DEGREE_RADIAN_UNIT,
- 40000.0f / GYRO_RAW_RESOLUTION * DEGREE_RADIAN_UNIT};
-
- ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifySensorWasCalled(&args));
- ASSERT_EQ(args.source, AINPUT_SOURCE_SENSOR);
- ASSERT_EQ(args.deviceId, DEVICE_ID);
- ASSERT_EQ(args.sensorType, InputDeviceSensorType::GYROSCOPE);
- ASSERT_EQ(args.accuracy, InputDeviceSensorAccuracy::ACCURACY_HIGH);
- ASSERT_EQ(args.hwTimestamp, ARBITRARY_TIME);
- ASSERT_EQ(args.values, values);
- mapper.flushSensor(InputDeviceSensorType::GYROSCOPE);
-}
-
// --- KeyboardInputMapperTest ---
class KeyboardInputMapperTest : public InputMapperTest {
@@ -4005,6 +3866,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/SensorInputMapper_test.cpp b/services/inputflinger/tests/SensorInputMapper_test.cpp
new file mode 100644
index 0000000..01814a6
--- /dev/null
+++ b/services/inputflinger/tests/SensorInputMapper_test.cpp
@@ -0,0 +1,183 @@
+/*
+ * 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.
+ */
+
+#include "SensorInputMapper.h"
+
+#include <vector>
+
+#include <EventHub.h>
+#include <NotifyArgs.h>
+#include <gtest/gtest.h>
+#include <input/Input.h>
+#include <input/InputDevice.h>
+#include <linux/input-event-codes.h>
+
+#include "InputMapperTest.h"
+
+namespace android {
+
+class SensorInputMapperTest : public InputMapperTest {
+protected:
+ static const int32_t ACCEL_RAW_MIN;
+ static const int32_t ACCEL_RAW_MAX;
+ static const int32_t ACCEL_RAW_FUZZ;
+ static const int32_t ACCEL_RAW_FLAT;
+ static const int32_t ACCEL_RAW_RESOLUTION;
+
+ static const int32_t GYRO_RAW_MIN;
+ static const int32_t GYRO_RAW_MAX;
+ static const int32_t GYRO_RAW_FUZZ;
+ static const int32_t GYRO_RAW_FLAT;
+ static const int32_t GYRO_RAW_RESOLUTION;
+
+ static const float GRAVITY_MS2_UNIT;
+ static const float DEGREE_RADIAN_UNIT;
+
+ void prepareAccelAxes();
+ void prepareGyroAxes();
+ void setAccelProperties();
+ void setGyroProperties();
+ void SetUp() override { InputMapperTest::SetUp(DEVICE_CLASSES | InputDeviceClass::SENSOR); }
+};
+
+const int32_t SensorInputMapperTest::ACCEL_RAW_MIN = -32768;
+const int32_t SensorInputMapperTest::ACCEL_RAW_MAX = 32768;
+const int32_t SensorInputMapperTest::ACCEL_RAW_FUZZ = 16;
+const int32_t SensorInputMapperTest::ACCEL_RAW_FLAT = 0;
+const int32_t SensorInputMapperTest::ACCEL_RAW_RESOLUTION = 8192;
+
+const int32_t SensorInputMapperTest::GYRO_RAW_MIN = -2097152;
+const int32_t SensorInputMapperTest::GYRO_RAW_MAX = 2097152;
+const int32_t SensorInputMapperTest::GYRO_RAW_FUZZ = 16;
+const int32_t SensorInputMapperTest::GYRO_RAW_FLAT = 0;
+const int32_t SensorInputMapperTest::GYRO_RAW_RESOLUTION = 1024;
+
+const float SensorInputMapperTest::GRAVITY_MS2_UNIT = 9.80665f;
+const float SensorInputMapperTest::DEGREE_RADIAN_UNIT = 0.0174533f;
+
+void SensorInputMapperTest::prepareAccelAxes() {
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_X, ACCEL_RAW_MIN, ACCEL_RAW_MAX, ACCEL_RAW_FUZZ,
+ ACCEL_RAW_FLAT, ACCEL_RAW_RESOLUTION);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_Y, ACCEL_RAW_MIN, ACCEL_RAW_MAX, ACCEL_RAW_FUZZ,
+ ACCEL_RAW_FLAT, ACCEL_RAW_RESOLUTION);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_Z, ACCEL_RAW_MIN, ACCEL_RAW_MAX, ACCEL_RAW_FUZZ,
+ ACCEL_RAW_FLAT, ACCEL_RAW_RESOLUTION);
+}
+
+void SensorInputMapperTest::prepareGyroAxes() {
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_RX, GYRO_RAW_MIN, GYRO_RAW_MAX, GYRO_RAW_FUZZ,
+ GYRO_RAW_FLAT, GYRO_RAW_RESOLUTION);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_RY, GYRO_RAW_MIN, GYRO_RAW_MAX, GYRO_RAW_FUZZ,
+ GYRO_RAW_FLAT, GYRO_RAW_RESOLUTION);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_RZ, GYRO_RAW_MIN, GYRO_RAW_MAX, GYRO_RAW_FUZZ,
+ GYRO_RAW_FLAT, GYRO_RAW_RESOLUTION);
+}
+
+void SensorInputMapperTest::setAccelProperties() {
+ mFakeEventHub->addSensorAxis(EVENTHUB_ID, /* absCode */ 0, InputDeviceSensorType::ACCELEROMETER,
+ /* sensorDataIndex */ 0);
+ mFakeEventHub->addSensorAxis(EVENTHUB_ID, /* absCode */ 1, InputDeviceSensorType::ACCELEROMETER,
+ /* sensorDataIndex */ 1);
+ mFakeEventHub->addSensorAxis(EVENTHUB_ID, /* absCode */ 2, InputDeviceSensorType::ACCELEROMETER,
+ /* sensorDataIndex */ 2);
+ mFakeEventHub->setMscEvent(EVENTHUB_ID, MSC_TIMESTAMP);
+ addConfigurationProperty("sensor.accelerometer.reportingMode", "0");
+ addConfigurationProperty("sensor.accelerometer.maxDelay", "100000");
+ addConfigurationProperty("sensor.accelerometer.minDelay", "5000");
+ addConfigurationProperty("sensor.accelerometer.power", "1.5");
+}
+
+void SensorInputMapperTest::setGyroProperties() {
+ mFakeEventHub->addSensorAxis(EVENTHUB_ID, /* absCode */ 3, InputDeviceSensorType::GYROSCOPE,
+ /* sensorDataIndex */ 0);
+ mFakeEventHub->addSensorAxis(EVENTHUB_ID, /* absCode */ 4, InputDeviceSensorType::GYROSCOPE,
+ /* sensorDataIndex */ 1);
+ mFakeEventHub->addSensorAxis(EVENTHUB_ID, /* absCode */ 5, InputDeviceSensorType::GYROSCOPE,
+ /* sensorDataIndex */ 2);
+ mFakeEventHub->setMscEvent(EVENTHUB_ID, MSC_TIMESTAMP);
+ addConfigurationProperty("sensor.gyroscope.reportingMode", "0");
+ addConfigurationProperty("sensor.gyroscope.maxDelay", "100000");
+ addConfigurationProperty("sensor.gyroscope.minDelay", "5000");
+ addConfigurationProperty("sensor.gyroscope.power", "0.8");
+}
+
+TEST_F(SensorInputMapperTest, GetSources) {
+ SensorInputMapper& mapper = constructAndAddMapper<SensorInputMapper>();
+
+ ASSERT_EQ(static_cast<uint32_t>(AINPUT_SOURCE_SENSOR), mapper.getSources());
+}
+
+TEST_F(SensorInputMapperTest, ProcessAccelerometerSensor) {
+ setAccelProperties();
+ prepareAccelAxes();
+ SensorInputMapper& mapper = constructAndAddMapper<SensorInputMapper>();
+
+ ASSERT_TRUE(mapper.enableSensor(InputDeviceSensorType::ACCELEROMETER,
+ std::chrono::microseconds(10000),
+ std::chrono::microseconds(0)));
+ ASSERT_TRUE(mFakeEventHub->isDeviceEnabled(EVENTHUB_ID));
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_X, 20000);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_Y, -20000);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_Z, 40000);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_MSC, MSC_TIMESTAMP, 1000);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
+
+ NotifySensorArgs args;
+ std::vector<float> values = {20000.0f / ACCEL_RAW_RESOLUTION * GRAVITY_MS2_UNIT,
+ -20000.0f / ACCEL_RAW_RESOLUTION * GRAVITY_MS2_UNIT,
+ 40000.0f / ACCEL_RAW_RESOLUTION * GRAVITY_MS2_UNIT};
+
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifySensorWasCalled(&args));
+ ASSERT_EQ(args.source, AINPUT_SOURCE_SENSOR);
+ ASSERT_EQ(args.deviceId, DEVICE_ID);
+ ASSERT_EQ(args.sensorType, InputDeviceSensorType::ACCELEROMETER);
+ ASSERT_EQ(args.accuracy, InputDeviceSensorAccuracy::ACCURACY_HIGH);
+ ASSERT_EQ(args.hwTimestamp, ARBITRARY_TIME);
+ ASSERT_EQ(args.values, values);
+ mapper.flushSensor(InputDeviceSensorType::ACCELEROMETER);
+}
+
+TEST_F(SensorInputMapperTest, ProcessGyroscopeSensor) {
+ setGyroProperties();
+ prepareGyroAxes();
+ SensorInputMapper& mapper = constructAndAddMapper<SensorInputMapper>();
+
+ ASSERT_TRUE(mapper.enableSensor(InputDeviceSensorType::GYROSCOPE,
+ std::chrono::microseconds(10000),
+ std::chrono::microseconds(0)));
+ ASSERT_TRUE(mFakeEventHub->isDeviceEnabled(EVENTHUB_ID));
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_RX, 20000);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_RY, -20000);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_RZ, 40000);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_MSC, MSC_TIMESTAMP, 1000);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
+
+ NotifySensorArgs args;
+ std::vector<float> values = {20000.0f / GYRO_RAW_RESOLUTION * DEGREE_RADIAN_UNIT,
+ -20000.0f / GYRO_RAW_RESOLUTION * DEGREE_RADIAN_UNIT,
+ 40000.0f / GYRO_RAW_RESOLUTION * DEGREE_RADIAN_UNIT};
+
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifySensorWasCalled(&args));
+ ASSERT_EQ(args.source, AINPUT_SOURCE_SENSOR);
+ ASSERT_EQ(args.deviceId, DEVICE_ID);
+ ASSERT_EQ(args.sensorType, InputDeviceSensorType::GYROSCOPE);
+ ASSERT_EQ(args.accuracy, InputDeviceSensorAccuracy::ACCURACY_HIGH);
+ ASSERT_EQ(args.hwTimestamp, ARBITRARY_TIME);
+ ASSERT_EQ(args.values, values);
+ mapper.flushSensor(InputDeviceSensorType::GYROSCOPE);
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/inputflinger/tests/TestEventMatchers.h b/services/inputflinger/tests/TestEventMatchers.h
index 6fa3365..7078e49 100644
--- a/services/inputflinger/tests/TestEventMatchers.h
+++ b/services/inputflinger/tests/TestEventMatchers.h
@@ -108,20 +108,33 @@
using is_gtest_matcher = void;
explicit WithMotionActionMatcher(int32_t action) : mAction(action) {}
- bool MatchAndExplain(const NotifyMotionArgs& args, std::ostream*) const {
- bool matches = mAction == args.action;
- if (args.action == AMOTION_EVENT_ACTION_CANCEL) {
- matches &= (args.flags & AMOTION_EVENT_FLAG_CANCELED) != 0;
+ bool MatchAndExplain(const NotifyMotionArgs& args,
+ testing::MatchResultListener* listener) const {
+ if (mAction != args.action) {
+ *listener << "expected " << MotionEvent::actionToString(mAction) << ", but got "
+ << MotionEvent::actionToString(args.action);
+ return false;
}
- return matches;
+ if (args.action == AMOTION_EVENT_ACTION_CANCEL &&
+ (args.flags & AMOTION_EVENT_FLAG_CANCELED) == 0) {
+ *listener << "event with CANCEL action is missing FLAG_CANCELED";
+ return false;
+ }
+ return true;
}
- bool MatchAndExplain(const MotionEvent& event, std::ostream*) const {
- bool matches = mAction == event.getAction();
- if (event.getAction() == AMOTION_EVENT_ACTION_CANCEL) {
- matches &= (event.getFlags() & AMOTION_EVENT_FLAG_CANCELED) != 0;
+ bool MatchAndExplain(const MotionEvent& event, testing::MatchResultListener* listener) const {
+ if (mAction != event.getAction()) {
+ *listener << "expected " << MotionEvent::actionToString(mAction) << ", but got "
+ << MotionEvent::actionToString(event.getAction());
+ return false;
}
- return matches;
+ if (event.getAction() == AMOTION_EVENT_ACTION_CANCEL &&
+ (event.getFlags() & AMOTION_EVENT_FLAG_CANCELED) == 0) {
+ *listener << "event with CANCEL action is missing FLAG_CANCELED";
+ return false;
+ }
+ return true;
}
void DescribeTo(std::ostream* os) const {
@@ -540,6 +553,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/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h
index fa8270a..a1da39a 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 {
@@ -285,6 +288,7 @@
void notifyTouchpadHardwareState(const SelfContainedHardwareState& schs,
int32_t deviceId) override {}
void notifyTouchpadGestureInfo(GestureType type, int32_t deviceId) override {}
+ void notifyTouchpadThreeFingerTap() override {}
std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay(
const InputDeviceIdentifier& identifier,
const std::optional<KeyboardLayoutInfo> layoutInfo) override {
diff --git a/services/powermanager/tests/PowerHalWrapperAidlTest.cpp b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp
index 1589c99..f5c4fc5 100644
--- a/services/powermanager/tests/PowerHalWrapperAidlTest.cpp
+++ b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp
@@ -35,6 +35,7 @@
using aidl::android::hardware::power::Mode;
using aidl::android::hardware::power::SessionConfig;
using aidl::android::hardware::power::SessionTag;
+using aidl::android::hardware::power::SupportInfo;
using android::binder::Status;
using namespace android;
@@ -65,6 +66,7 @@
(int32_t tgid, int32_t uid, ChannelConfig* _aidl_return), (override));
MOCK_METHOD(ndk::ScopedAStatus, closeSessionChannel, (int32_t tgid, int32_t uid), (override));
MOCK_METHOD(ndk::ScopedAStatus, getHintSessionPreferredRate, (int64_t * rate), (override));
+ MOCK_METHOD(ndk::ScopedAStatus, getSupportInfo, (SupportInfo * _aidl_return), (override));
MOCK_METHOD(ndk::ScopedAStatus, getInterfaceVersion, (int32_t * version), (override));
MOCK_METHOD(ndk::ScopedAStatus, getInterfaceHash, (std::string * hash), (override));
MOCK_METHOD(ndk::SpAIBinder, asBinder, (), (override));
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 7babd17..f1c79c1 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",
@@ -250,7 +284,6 @@
],
static_libs: [
"android.frameworks.displayservice@1.0",
- "libc++fs",
"libdisplayservicehidl",
"libserviceutils",
],
@@ -313,3 +346,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..8067ace 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -49,9 +49,7 @@
"libaidlcommonsupport",
"libprocessgroup",
"libprocessgroup_util",
- "libcgrouprc",
"libjsoncpp",
- "libcgrouprc_format",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
@@ -59,7 +57,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 +139,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 +151,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 +167,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/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 22ab3d9..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;
@@ -1678,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 48ebc32..3e0c390 100644
--- a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
@@ -26,9 +26,8 @@
#include <gtest/gtest.h>
#include <renderengine/mock/RenderEngine.h>
-#include "MockHWComposer.h"
#include "TimeStats/TimeStats.h"
-#include "gmock/gmock.h"
+#include "mock/DisplayHardware/MockHWComposer.h"
using namespace com::android::graphics::surfaceflinger;
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 1c18cd2..fe7dd9a 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -40,8 +40,8 @@
#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 {
@@ -785,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));
@@ -822,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));
@@ -858,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));
@@ -896,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,
@@ -4932,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));
@@ -4966,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));
@@ -5006,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/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 402a3d2..c743ea2 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -201,6 +201,10 @@
return mPowerMode != hal::PowerMode::OFF;
}
+bool DisplayDevice::isRefreshable() const {
+ return mPowerMode == hal::PowerMode::DOZE || mPowerMode == hal::PowerMode::ON;
+}
+
ui::Dataspace DisplayDevice::getCompositionDataSpace() const {
return mCompositionDisplay->getState().dataspace;
}
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 3e3f558..d09a6b3 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -173,6 +173,7 @@
hardware::graphics::composer::hal::PowerMode getPowerMode() const;
void setPowerMode(hardware::graphics::composer::hal::PowerMode);
bool isPoweredOn() const;
+ bool isRefreshable() const;
void tracePowerMode();
// Enables layer caching on this DisplayDevice
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/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/LayerHierarchy.cpp b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp
index d709530..da536b6 100644
--- a/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp
@@ -166,7 +166,8 @@
}
out << "(Mirroring) ";
}
- out << *mLayer;
+
+ out << *mLayer << " pid=" << mLayer->ownerPid.val() << " uid=" << mLayer->ownerUid.val();
}
for (size_t i = 0; i < mChildren.size(); i++) {
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
index e5f6b7b..a8be50a 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
@@ -250,6 +250,7 @@
if (drawShadows()) reason << " shadowSettings.length=" << shadowSettings.length;
if (backgroundBlurRadius > 0) reason << " backgroundBlurRadius=" << backgroundBlurRadius;
if (blurRegions.size() > 0) reason << " blurRegions.size()=" << blurRegions.size();
+ if (contentDirty) reason << " contentDirty";
return reason.str();
}
@@ -359,8 +360,9 @@
uint32_t displayRotationFlags) {
clientChanges = requested.what;
changes = requested.changes;
- contentDirty = requested.what & layer_state_t::CONTENT_DIRTY;
- hasReadyFrame = requested.autoRefresh;
+ autoRefresh = requested.autoRefresh;
+ contentDirty = requested.what & layer_state_t::CONTENT_DIRTY || autoRefresh;
+ hasReadyFrame = autoRefresh;
sidebandStreamHasFrame = requested.hasSidebandStreamFrame();
updateSurfaceDamage(requested, requested.hasReadyFrame(), forceFullDamage, surfaceDamage);
@@ -513,6 +515,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/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
index b7d4cc5..b8df3ed 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
@@ -77,6 +77,7 @@
gui::LayerMetadata layerMetadata;
gui::LayerMetadata relativeLayerMetadata;
bool hasReadyFrame; // used in post composition to check if there is another frame ready
+ bool autoRefresh;
ui::Transform localTransformInverse;
gui::WindowInfo inputInfo;
ui::Transform localTransform;
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index 10e212e..7569c1b 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -314,8 +314,8 @@
void clearChanges(LayerSnapshot& snapshot) {
snapshot.changes.clear();
snapshot.clientChanges = 0;
- snapshot.contentDirty = false;
- snapshot.hasReadyFrame = false;
+ snapshot.contentDirty = snapshot.autoRefresh;
+ snapshot.hasReadyFrame = snapshot.autoRefresh;
snapshot.sidebandStreamHasFrame = false;
snapshot.surfaceDamage.clear();
}
@@ -724,10 +724,12 @@
if (args.displayChanges) snapshot.changes |= RequestedLayerState::Changes::Geometry;
snapshot.reachablilty = LayerSnapshot::Reachablilty::Reachable;
snapshot.clientChanges |= (parentSnapshot.clientChanges & layer_state_t::AFFECTS_CHILDREN);
+ // mark the content as dirty if the parent state changes can dirty the child's content (for
+ // example alpha)
+ snapshot.contentDirty |= (snapshot.clientChanges & layer_state_t::CONTENT_DIRTY) != 0;
snapshot.isHiddenByPolicyFromParent = parentSnapshot.isHiddenByPolicyFromParent ||
parentSnapshot.invalidTransform || requested.isHiddenByPolicy() ||
(args.excludeLayerIds.find(path.id) != args.excludeLayerIds.end());
-
const bool forceUpdate = args.forceUpdate == ForceUpdateFlags::ALL ||
snapshot.clientChanges & layer_state_t::eReparent ||
snapshot.changes.any(RequestedLayerState::Changes::Visibility |
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 e5dc2ee..20ba45f 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();
}
@@ -681,8 +689,20 @@
listener->onReleaseBuffer(callbackId, fence, currentMaxAcquiredBufferCount);
}
- if (mBufferReleaseChannel) {
- mBufferReleaseChannel->writeReleaseFence(callbackId, fence, currentMaxAcquiredBufferCount);
+ if (!mBufferReleaseChannel) {
+ return;
+ }
+
+ status_t status = mBufferReleaseChannel->writeReleaseFence(callbackId, fence,
+ currentMaxAcquiredBufferCount);
+ if (status != OK) {
+ int error = -status;
+ // callReleaseBufferCallback is called during Layer's destructor. In this case, it's
+ // expected to receive connection errors.
+ if (error != EPIPE && error != ECONNRESET) {
+ ALOGD("[%s] writeReleaseFence failed. error %d (%s)", getDebugName(), error,
+ strerror(error));
+ }
}
}
@@ -1261,8 +1281,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 871ad5e..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};
diff --git a/services/surfaceflinger/LayerFE.cpp b/services/surfaceflinger/LayerFE.cpp
index f64ba9e..a346981 100644
--- a/services/surfaceflinger/LayerFE.cpp
+++ b/services/surfaceflinger/LayerFE.cpp
@@ -174,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 011fd9e..21d3396 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -353,22 +353,13 @@
sampledBounds.getSize(), ui::Dataspace::V0_SRGB, displayWeak,
RenderArea::Options::CAPTURE_SECURE_LAYERS);
- FenceResult fenceResult;
- if (FlagManager::getInstance().single_hop_screenshot() &&
- mFlinger.mRenderEngine->isThreaded()) {
- std::vector<sp<LayerFE>> layerFEs;
- auto displayState = mFlinger.getSnapshotsFromMainThread(renderAreaBuilder,
- getLayerSnapshotsFn, layerFEs);
- fenceResult = mFlinger.captureScreenshot(renderAreaBuilder, buffer, kRegionSampling,
- kGrayscale, kIsProtected, kAttachGainmap, nullptr,
- displayState, layerFEs)
- .get();
- } else {
- fenceResult = mFlinger.captureScreenshotLegacy(renderAreaBuilder, getLayerSnapshotsFn,
- buffer, kRegionSampling, kGrayscale,
- kIsProtected, kAttachGainmap, nullptr)
- .get();
- }
+ std::vector<std::pair<Layer*, sp<LayerFE>>> layers;
+ auto displayState =
+ mFlinger.getSnapshotsFromMainThread(renderAreaBuilder, getLayerSnapshotsFn, layers);
+ FenceResult fenceResult =
+ mFlinger.captureScreenshot(renderAreaBuilder, buffer, kRegionSampling, kGrayscale,
+ kIsProtected, kAttachGainmap, nullptr, displayState, layers)
+ .get();
if (fenceResult.ok()) {
fenceResult.value()->waitForever(LOG_TAG);
}
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index e385f18..7729671 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -420,6 +420,16 @@
mCondition.notify_all();
}
+void EventThread::omitVsyncDispatching(bool omitted) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (!mVSyncState || mVSyncState->omitted == omitted) {
+ return;
+ }
+
+ mVSyncState->omitted = omitted;
+ mCondition.notify_all();
+}
+
void EventThread::onVsync(nsecs_t vsyncTime, nsecs_t wakeupTime, nsecs_t readyTime) {
std::lock_guard<std::mutex> lock(mMutex);
mLastVsyncCallbackTime = TimePoint::fromNs(vsyncTime);
@@ -521,7 +531,17 @@
}
if (mVSyncState && vsyncRequested) {
- mState = mVSyncState->synthetic ? State::SyntheticVSync : State::VSync;
+ const bool vsyncOmitted =
+ FlagManager::getInstance().no_vsyncs_on_screen_off() && mVSyncState->omitted;
+ if (vsyncOmitted) {
+ mState = State::Idle;
+ SFTRACE_INT("VsyncPendingScreenOn", 1);
+ } else {
+ mState = mVSyncState->synthetic ? State::SyntheticVSync : State::VSync;
+ if (FlagManager::getInstance().no_vsyncs_on_screen_off()) {
+ SFTRACE_INT("VsyncPendingScreenOn", 0);
+ }
+ }
} else {
ALOGW_IF(!mVSyncState, "Ignoring VSYNC request while display is disconnected");
mState = State::Idle;
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index c3c7eb0..2daf126 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -106,6 +106,8 @@
// Feed clients with fake VSYNC, e.g. while the display is off.
virtual void enableSyntheticVsync(bool) = 0;
+ virtual void omitVsyncDispatching(bool) = 0;
+
virtual void onHotplugReceived(PhysicalDisplayId displayId, bool connected) = 0;
virtual void onHotplugConnectionError(int32_t connectionError) = 0;
@@ -165,6 +167,8 @@
void enableSyntheticVsync(bool) override;
+ void omitVsyncDispatching(bool) override;
+
void onHotplugReceived(PhysicalDisplayId displayId, bool connected) override;
void onHotplugConnectionError(int32_t connectionError) override;
@@ -240,6 +244,9 @@
// True if VSYNC should be faked, e.g. when display is off.
bool synthetic = false;
+
+ // True if VSYNC should not be delivered to apps. Used when the display is off.
+ bool omitted = false;
};
// TODO(b/74619554): Create per-display threads waiting on respective VSYNC signals,
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
index ab9014e..ad067be 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();
@@ -1638,9 +1652,9 @@
FpsRange RefreshRateSelector::getFrameRateCategoryRange(FrameRateCategory category) {
switch (category) {
case FrameRateCategory::High:
- return FpsRange{90_Hz, 120_Hz};
+ return FpsRange{kFrameRateCategoryRateHigh, 120_Hz};
case FrameRateCategory::Normal:
- return FpsRange{60_Hz, 120_Hz};
+ return FpsRange{kFrameRateCategoryRateNormal, 120_Hz};
case FrameRateCategory::Low:
return FpsRange{48_Hz, 120_Hz};
case FrameRateCategory::HighHint:
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.h b/services/surfaceflinger/Scheduler/RefreshRateSelector.h
index a398c01..ee3a4f7 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.h
@@ -52,6 +52,12 @@
// The lowest Render Frame Rate that will ever be selected
static constexpr Fps kMinSupportedFrameRate = 20_Hz;
+ // Start range for FrameRateCategory Normal and High.
+ static constexpr Fps kFrameRateCategoryRateHigh = 90_Hz;
+ static constexpr Fps kFrameRateCategoryRateNormal = 60_Hz;
+ static constexpr std::pair<Fps, Fps> kFrameRateCategoryRates = {kFrameRateCategoryRateNormal,
+ kFrameRateCategoryRateHigh};
+
class Policy {
static constexpr int kAllowGroupSwitchingDefault = false;
@@ -433,6 +439,8 @@
bool isVrrDevice() const;
+ std::pair<Fps, Fps> getFrameRateCategoryRates() const { return kFrameRateCategoryRates; }
+
private:
friend struct TestableRefreshRateSelector;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index b83ff19..b8b1f59 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -405,6 +405,14 @@
eventThreadFor(Cycle::Render).enableSyntheticVsync(enable);
}
+void Scheduler::omitVsyncDispatching(bool omitted) {
+ eventThreadFor(Cycle::Render).omitVsyncDispatching(omitted);
+ // Note: If we don't couple Cycle::LastComposite event thread, there is a black screen
+ // after boot. This is most likely sysui or system_server dependency on sf instance
+ // Choreographer
+ eventThreadFor(Cycle::LastComposite).omitVsyncDispatching(omitted);
+}
+
void Scheduler::onFrameRateOverridesChanged() {
const auto [pacesetterId, supportsFrameRateOverrideByContent] = [this] {
std::scoped_lock lock(mDisplayLock);
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index c88b563..d029488 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -154,6 +154,7 @@
bool onDisplayModeChanged(PhysicalDisplayId, const FrameRateMode&) EXCLUDES(mPolicyLock);
void enableSyntheticVsync(bool = true) REQUIRES(kMainThreadContext);
+ void omitVsyncDispatching(bool) REQUIRES(kMainThreadContext);
void onHdcpLevelsChanged(Cycle, PhysicalDisplayId, int32_t, int32_t);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index acf50f0..532eebc 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>
@@ -91,6 +92,7 @@
#include <ui/DisplayStatInfo.h>
#include <ui/DisplayState.h>
#include <ui/DynamicDisplayInfo.h>
+#include <ui/FrameRateCategoryRate.h>
#include <ui/GraphicBufferAllocator.h>
#include <ui/HdrRenderTypeUtils.h>
#include <ui/LayerStack.h>
@@ -1008,7 +1010,8 @@
config.cacheUltraHDR =
base::GetBoolProperty("ro.surface_flinger.prime_shader_cache.ultrahdr"s, false);
config.cacheEdgeExtension =
- base::GetBoolProperty("debug.sf.edge_extension_shader"s, true);
+ base::GetBoolProperty("debug.sf.prime_shader_cache.edge_extension_shader"s,
+ true);
return getRenderEngine().primeCache(config);
});
@@ -1216,6 +1219,10 @@
info->activeDisplayModeId = ftl::to_underlying(mode.modePtr->getId());
info->renderFrameRate = mode.fps.getValue();
info->hasArrSupport = mode.modePtr->getVrrConfig() && FlagManager::getInstance().vrr_config();
+
+ const auto [normal, high] = display->refreshRateSelector().getFrameRateCategoryRates();
+ ui::FrameRateCategoryRate frameRateCategoryRate(normal.getValue(), high.getValue());
+ info->frameRateCategoryRate = frameRateCategoryRate;
info->activeColorMode = display->getCompositionDisplay()->getState().colorMode;
info->hdrCapabilities = filterOut4k30(display->getHdrCapabilities());
@@ -1655,19 +1662,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());
}
@@ -2522,17 +2532,13 @@
frontend::LayerSnapshot* snapshot = mLayerSnapshotBuilder.getSnapshot(it->second->sequence);
gui::GameMode gameMode = (snapshot) ? snapshot->gameMode : gui::GameMode::Unsupported;
mLayersWithQueuedFrames.emplace(it->second, gameMode);
- mLayersIdsWithQueuedFrames.emplace(it->second->sequence);
}
updateLayerHistory(latchTime);
mLayerSnapshotBuilder.forEachSnapshot([&](const frontend::LayerSnapshot& snapshot) {
- // update output dirty region if we have a queued buffer that is visible or a snapshot
- // recently became invisible
- // TODO(b/360050020) investigate if we need to update dirty region when layer color changes
- if ((snapshot.isVisible &&
- (mLayersIdsWithQueuedFrames.find(snapshot.path.id) !=
- mLayersIdsWithQueuedFrames.end())) ||
+ // update output's dirty region if a snapshot is visible and its
+ // content is dirty or if a snapshot recently became invisible
+ if ((snapshot.isVisible && snapshot.contentDirty) ||
(!snapshot.isVisible && snapshot.changes.test(Changes::Visibility))) {
Region visibleReg;
visibleReg.set(snapshot.transformedBoundsWithoutTransparentRegion);
@@ -2922,7 +2928,6 @@
mScheduler->modulateVsync({}, &VsyncModulator::onDisplayRefresh, hasGpuUseOrReuse);
mLayersWithQueuedFrames.clear();
- mLayersIdsWithQueuedFrames.clear();
doActiveLayersTracingIfNeeded(true, mVisibleRegionsDirty, pacesetterTarget.frameBeginTime(),
vsyncId);
@@ -3143,6 +3148,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;
@@ -3643,6 +3661,26 @@
return display;
}
+void SurfaceFlinger::incRefreshableDisplays() {
+ if (FlagManager::getInstance().no_vsyncs_on_screen_off()) {
+ mRefreshableDisplays++;
+ if (mRefreshableDisplays == 1) {
+ ftl::FakeGuard guard(kMainThreadContext);
+ mScheduler->omitVsyncDispatching(false);
+ }
+ }
+}
+
+void SurfaceFlinger::decRefreshableDisplays() {
+ if (FlagManager::getInstance().no_vsyncs_on_screen_off()) {
+ mRefreshableDisplays--;
+ if (mRefreshableDisplays == 0) {
+ ftl::FakeGuard guard(kMainThreadContext);
+ mScheduler->omitVsyncDispatching(true);
+ }
+ }
+}
+
void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken,
const DisplayDeviceState& state) {
ui::Size resolution(0, 0);
@@ -3734,6 +3772,10 @@
display->adjustRefreshRate(mScheduler->getPacesetterRefreshRate());
}
+ if (display->isRefreshable()) {
+ incRefreshableDisplays();
+ }
+
mDisplays.try_emplace(displayToken, std::move(display));
// For an external display, loadDisplayModes already attempted to select the same mode
@@ -3768,6 +3810,10 @@
} else {
mScheduler->unregisterDisplay(display->getPhysicalId(), mActiveDisplayId);
}
+
+ if (display->isRefreshable()) {
+ decRefreshableDisplays();
+ }
}
mDisplays.erase(displayToken);
@@ -3802,6 +3848,10 @@
if (display->isVirtual()) {
releaseVirtualDisplay(display->getVirtualId());
}
+
+ if (display->isRefreshable()) {
+ decRefreshableDisplays();
+ }
}
mDisplays.erase(displayToken);
@@ -5300,7 +5350,15 @@
activeDisplay->isPoweredOn(),
"Trying to change power mode on inactive display without powering off active display");
+ const bool couldRefresh = display->isRefreshable();
display->setPowerMode(mode);
+ const bool canRefresh = display->isRefreshable();
+
+ if (couldRefresh && !canRefresh) {
+ decRefreshableDisplays();
+ } else if (!couldRefresh && canRefresh) {
+ incRefreshableDisplays();
+ }
const auto activeMode = display->refreshRateSelector().getActiveMode().modePtr;
if (currentMode == hal::PowerMode::OFF) {
@@ -7141,9 +7199,10 @@
// typically a layer with DRM contents, or have the GRALLOC_USAGE_PROTECTED set on the buffer.
// A protected layer has no implication on whether it's secure, which is explicitly set by
// application to avoid being screenshot or drawn via unsecure display.
-bool SurfaceFlinger::layersHasProtectedLayer(const std::vector<sp<LayerFE>>& layers) const {
+bool SurfaceFlinger::layersHasProtectedLayer(
+ const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) const {
bool protectedLayerFound = false;
- for (auto& layerFE : layers) {
+ for (auto& [_, layerFE] : layers) {
protectedLayerFound |=
(layerFE->mSnapshot->isVisible && layerFE->mSnapshot->hasProtectedContent);
if (protectedLayerFound) {
@@ -7159,15 +7218,21 @@
// risk of deadlocks.
std::optional<SurfaceFlinger::OutputCompositionState> SurfaceFlinger::getSnapshotsFromMainThread(
RenderAreaBuilderVariant& renderAreaBuilder, GetLayerSnapshotsFunction getLayerSnapshotsFn,
- std::vector<sp<LayerFE>>& layerFEs) {
+ std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) {
return mScheduler
- ->schedule([=, this, &renderAreaBuilder, &layerFEs]() REQUIRES(kMainThreadContext) {
+ ->schedule([=, this, &renderAreaBuilder, &layers]() REQUIRES(kMainThreadContext) {
SFTRACE_NAME("getSnapshotsFromMainThread");
- auto layers = getLayerSnapshotsFn();
- for (auto& [layer, layerFE] : layers) {
- attachReleaseFenceFutureToLayer(layer, layerFE.get(), ui::INVALID_LAYER_STACK);
+ layers = getLayerSnapshotsFn();
+ // Non-threaded RenderEngine eventually returns to the main thread a 2nd time
+ // to complete the screenshot. Release fences should only be added during the 2nd
+ // hop to main thread in order to avoid potential deadlocks from waiting for the
+ // the future fence to fire.
+ if (mRenderEngine->isThreaded()) {
+ for (auto& [layer, layerFE] : layers) {
+ attachReleaseFenceFutureToLayer(layer, layerFE.get(),
+ ui::INVALID_LAYER_STACK);
+ }
}
- layerFEs = extractLayerFEs(layers);
return getDisplayStateFromRenderAreaBuilder(renderAreaBuilder);
})
.get();
@@ -7188,79 +7253,41 @@
return;
}
- if (FlagManager::getInstance().single_hop_screenshot() && mRenderEngine->isThreaded()) {
- std::vector<sp<LayerFE>> layerFEs;
- auto displayState =
- getSnapshotsFromMainThread(renderAreaBuilder, getLayerSnapshotsFn, layerFEs);
+ std::vector<std::pair<Layer*, sp<LayerFE>>> layers;
+ auto displayState = getSnapshotsFromMainThread(renderAreaBuilder, getLayerSnapshotsFn, layers);
- const bool supportsProtected = getRenderEngine().supportsProtectedContent();
- bool hasProtectedLayer = false;
- if (allowProtected && supportsProtected) {
- hasProtectedLayer = layersHasProtectedLayer(layerFEs);
- }
- const bool isProtected = hasProtectedLayer && allowProtected && supportsProtected;
- const uint32_t usage = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER |
- GRALLOC_USAGE_HW_TEXTURE |
- (isProtected ? GRALLOC_USAGE_PROTECTED
- : GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
- sp<GraphicBuffer> buffer =
- getFactory().createGraphicBuffer(bufferSize.getWidth(), bufferSize.getHeight(),
- static_cast<android_pixel_format>(reqPixelFormat),
- 1 /* layerCount */, usage, "screenshot");
-
- const status_t bufferStatus = buffer->initCheck();
- if (bufferStatus != OK) {
- // Animations may end up being really janky, but don't crash here.
- // Otherwise an irreponsible process may cause an SF crash by allocating
- // too much.
- ALOGE("%s: Buffer failed to allocate: %d", __func__, bufferStatus);
- invokeScreenCaptureError(bufferStatus, captureListener);
- return;
- }
- const std::shared_ptr<renderengine::ExternalTexture> texture = std::make_shared<
- renderengine::impl::ExternalTexture>(buffer, getRenderEngine(),
- renderengine::impl::ExternalTexture::Usage::
- WRITEABLE);
- auto futureFence = captureScreenshot(renderAreaBuilder, texture, false /* regionSampling */,
- grayscale, isProtected, attachGainmap, captureListener,
- displayState, layerFEs);
- futureFence.get();
-
- } else {
- const bool supportsProtected = getRenderEngine().supportsProtectedContent();
- bool hasProtectedLayer = false;
- if (allowProtected && supportsProtected) {
- auto layers = mScheduler->schedule([=]() { return getLayerSnapshotsFn(); }).get();
- hasProtectedLayer = layersHasProtectedLayer(extractLayerFEs(layers));
- }
- const bool isProtected = hasProtectedLayer && allowProtected && supportsProtected;
- const uint32_t usage = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER |
- GRALLOC_USAGE_HW_TEXTURE |
- (isProtected ? GRALLOC_USAGE_PROTECTED
- : GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
- sp<GraphicBuffer> buffer =
- getFactory().createGraphicBuffer(bufferSize.getWidth(), bufferSize.getHeight(),
- static_cast<android_pixel_format>(reqPixelFormat),
- 1 /* layerCount */, usage, "screenshot");
-
- const status_t bufferStatus = buffer->initCheck();
- if (bufferStatus != OK) {
- // Animations may end up being really janky, but don't crash here.
- // Otherwise an irreponsible process may cause an SF crash by allocating
- // too much.
- ALOGE("%s: Buffer failed to allocate: %d", __func__, bufferStatus);
- invokeScreenCaptureError(bufferStatus, captureListener);
- return;
- }
- const std::shared_ptr<renderengine::ExternalTexture> texture = std::make_shared<
- renderengine::impl::ExternalTexture>(buffer, getRenderEngine(),
- renderengine::impl::ExternalTexture::Usage::
- WRITEABLE);
- auto futureFence = captureScreenshotLegacy(renderAreaBuilder, getLayerSnapshotsFn, texture,
- false /* regionSampling */, grayscale,
- isProtected, attachGainmap, captureListener);
- futureFence.get();
+ const bool supportsProtected = getRenderEngine().supportsProtectedContent();
+ bool hasProtectedLayer = false;
+ if (allowProtected && supportsProtected) {
+ hasProtectedLayer = layersHasProtectedLayer(layers);
}
+ const bool isProtected = hasProtectedLayer && allowProtected && supportsProtected;
+ const uint32_t usage = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER |
+ GRALLOC_USAGE_HW_TEXTURE |
+ (isProtected ? GRALLOC_USAGE_PROTECTED
+ : GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
+ sp<GraphicBuffer> buffer =
+ getFactory().createGraphicBuffer(bufferSize.getWidth(), bufferSize.getHeight(),
+ static_cast<android_pixel_format>(reqPixelFormat),
+ 1 /* layerCount */, usage, "screenshot");
+
+ const status_t bufferStatus = buffer->initCheck();
+ if (bufferStatus != OK) {
+ // Animations may end up being really janky, but don't crash here.
+ // Otherwise an irreponsible process may cause an SF crash by allocating
+ // too much.
+ ALOGE("%s: Buffer failed to allocate: %d", __func__, bufferStatus);
+ invokeScreenCaptureError(bufferStatus, captureListener);
+ return;
+ }
+ const std::shared_ptr<renderengine::ExternalTexture> texture = std::make_shared<
+ renderengine::impl::ExternalTexture>(buffer, getRenderEngine(),
+ renderengine::impl::ExternalTexture::Usage::
+ WRITEABLE);
+ auto futureFence =
+ captureScreenshot(renderAreaBuilder, texture, false /* regionSampling */, grayscale,
+ isProtected, attachGainmap, captureListener, displayState, layers);
+ futureFence.get();
}
std::optional<SurfaceFlinger::OutputCompositionState>
@@ -7299,22 +7326,13 @@
return std::nullopt;
}
-std::vector<sp<LayerFE>> SurfaceFlinger::extractLayerFEs(
- const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) const {
- std::vector<sp<LayerFE>> layerFEs;
- layerFEs.reserve(layers.size());
- for (const auto& [_, layerFE] : layers) {
- layerFEs.push_back(layerFE);
- }
- return layerFEs;
-}
-
ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot(
const RenderAreaBuilderVariant& renderAreaBuilder,
const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling,
bool grayscale, bool isProtected, bool attachGainmap,
const sp<IScreenCaptureListener>& captureListener,
- std::optional<OutputCompositionState>& displayState, std::vector<sp<LayerFE>>& layerFEs) {
+ std::optional<OutputCompositionState>& displayState,
+ std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) {
SFTRACE_CALL();
ScreenCaptureResults captureResults;
@@ -7333,11 +7351,9 @@
float displayBrightnessNits = displayState.value().displayBrightnessNits;
float sdrWhitePointNits = displayState.value().sdrWhitePointNits;
- // Empty vector needed to pass into renderScreenImpl for legacy path
- std::vector<std::pair<Layer*, sp<android::LayerFE>>> layers;
ftl::SharedFuture<FenceResult> renderFuture =
renderScreenImpl(renderArea.get(), buffer, regionSampling, grayscale, isProtected,
- attachGainmap, captureResults, displayState, layers, layerFEs);
+ captureResults, displayState, layers);
if (captureResults.capturedHdrLayers && attachGainmap &&
FlagManager::getInstance().true_hdr_screenshots()) {
@@ -7372,8 +7388,7 @@
ScreenCaptureResults unusedResults;
ftl::SharedFuture<FenceResult> hdrRenderFuture =
renderScreenImpl(renderArea.get(), hdrTexture, regionSampling, grayscale,
- isProtected, attachGainmap, unusedResults, displayState,
- layers, layerFEs);
+ isProtected, unusedResults, displayState, layers);
renderFuture =
ftl::Future(std::move(renderFuture))
@@ -7419,75 +7434,14 @@
return renderFuture;
}
-ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshotLegacy(
- RenderAreaBuilderVariant renderAreaBuilder, GetLayerSnapshotsFunction getLayerSnapshotsFn,
- const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling,
- bool grayscale, bool isProtected, bool attachGainmap,
- const sp<IScreenCaptureListener>& captureListener) {
- SFTRACE_CALL();
-
- auto takeScreenshotFn = [=, this, renderAreaBuilder = std::move(renderAreaBuilder)]() REQUIRES(
- kMainThreadContext) mutable -> ftl::SharedFuture<FenceResult> {
- auto layers = getLayerSnapshotsFn();
- for (auto& [layer, layerFE] : layers) {
- attachReleaseFenceFutureToLayer(layer, layerFE.get(), ui::INVALID_LAYER_STACK);
- }
- auto displayState = getDisplayStateFromRenderAreaBuilder(renderAreaBuilder);
-
- ScreenCaptureResults captureResults;
- std::unique_ptr<const RenderArea> renderArea =
- std::visit([](auto&& arg) -> std::unique_ptr<RenderArea> { return arg.build(); },
- renderAreaBuilder);
-
- if (!renderArea) {
- ALOGW("Skipping screen capture because of invalid render area.");
- if (captureListener) {
- captureResults.fenceResult = base::unexpected(NO_MEMORY);
- captureListener->onScreenCaptureCompleted(captureResults);
- }
- return ftl::yield<FenceResult>(base::unexpected(NO_ERROR)).share();
- }
-
- auto layerFEs = extractLayerFEs(layers);
- ftl::SharedFuture<FenceResult> renderFuture =
- renderScreenImpl(renderArea.get(), buffer, regionSampling, grayscale, isProtected,
- attachGainmap, captureResults, displayState, layers, layerFEs);
-
- if (captureListener) {
- // Defer blocking on renderFuture back to the Binder thread.
- return ftl::Future(std::move(renderFuture))
- .then([captureListener, captureResults = std::move(captureResults)](
- FenceResult fenceResult) mutable -> FenceResult {
- captureResults.fenceResult = std::move(fenceResult);
- captureListener->onScreenCaptureCompleted(captureResults);
- return base::unexpected(NO_ERROR);
- })
- .share();
- }
- return renderFuture;
- };
-
- // TODO(b/294936197): Run takeScreenshotsFn() in a binder thread to reduce the number
- // of calls on the main thread.
- auto future =
- mScheduler->schedule(FTL_FAKE_GUARD(kMainThreadContext, std::move(takeScreenshotFn)));
-
- // Flatten nested futures.
- auto chain = ftl::Future(std::move(future)).then([](ftl::SharedFuture<FenceResult> future) {
- return future;
- });
-
- return chain.share();
-}
-
ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl(
const RenderArea* renderArea, const std::shared_ptr<renderengine::ExternalTexture>& buffer,
- bool regionSampling, bool grayscale, bool isProtected, bool attachGainmap,
- ScreenCaptureResults& captureResults, std::optional<OutputCompositionState>& displayState,
- std::vector<std::pair<Layer*, sp<LayerFE>>>& layers, std::vector<sp<LayerFE>>& layerFEs) {
+ bool regionSampling, bool grayscale, bool isProtected, ScreenCaptureResults& captureResults,
+ std::optional<OutputCompositionState>& displayState,
+ std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) {
SFTRACE_CALL();
- for (auto& layerFE : layerFEs) {
+ for (auto& [_, layerFE] : layers) {
frontend::LayerSnapshot* snapshot = layerFE->mSnapshot.get();
captureResults.capturedSecureLayers |= (snapshot->isVisible && snapshot->isSecure);
captureResults.capturedHdrLayers |= isHdrLayer(*snapshot);
@@ -7546,29 +7500,32 @@
captureResults.buffer = capturedBuffer->getBuffer();
ui::LayerStack layerStack{ui::DEFAULT_LAYER_STACK};
- if (!layerFEs.empty()) {
- const sp<LayerFE>& layerFE = layerFEs.back();
+ if (!layers.empty()) {
+ const sp<LayerFE>& layerFE = layers.back().second;
layerStack = layerFE->getCompositionState()->outputFilter.layerStack;
}
- auto copyLayerFEs = [&layerFEs]() {
- std::vector<sp<compositionengine::LayerFE>> ceLayerFEs;
- ceLayerFEs.reserve(layerFEs.size());
- for (const auto& layerFE : layerFEs) {
- ceLayerFEs.push_back(layerFE);
- }
- return ceLayerFEs;
- };
-
auto present = [this, buffer = capturedBuffer, dataspace = captureResults.capturedDataspace,
sdrWhitePointNits, displayBrightnessNits, grayscale, isProtected,
- layerFEs = copyLayerFEs(), layerStack, regionSampling,
+ layers = std::move(layers), layerStack, regionSampling,
renderArea = std::move(renderArea), renderIntent,
enableLocalTonemapping]() -> FenceResult {
std::unique_ptr<compositionengine::CompositionEngine> compositionEngine =
mFactory.createCompositionEngine();
compositionEngine->setRenderEngine(mRenderEngine.get());
+ std::vector<sp<compositionengine::LayerFE>> layerFEs;
+ layerFEs.reserve(layers.size());
+ for (auto& [layer, layerFE] : layers) {
+ // Release fences were not yet added for non-threaded render engine. To avoid
+ // deadlocks between main thread and binder threads waiting for the future fence
+ // result, fences should be added to layers in the same hop onto the main thread.
+ if (!mRenderEngine->isThreaded()) {
+ attachReleaseFenceFutureToLayer(layer, layerFE.get(), ui::INVALID_LAYER_STACK);
+ }
+ layerFEs.push_back(layerFE);
+ }
+
compositionengine::Output::ColorProfile colorProfile{.dataspace = dataspace,
.renderIntent = renderIntent};
@@ -7626,13 +7583,9 @@
//
// 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() && mRenderEngine->isThreaded()) {
- presentFuture = ftl::yield(present()).share();
- } else {
- presentFuture = mRenderEngine->isThreaded() ? ftl::defer(std::move(present)).share()
- : ftl::yield(present()).share();
- }
+ ftl::SharedFuture<FenceResult> presentFuture = mRenderEngine->isThreaded()
+ ? ftl::yield(present()).share()
+ : mScheduler->schedule(std::move(present)).share();
return presentFuture;
}
@@ -8584,6 +8537,9 @@
outInfo->activeDisplayModeId = info.activeDisplayModeId;
outInfo->renderFrameRate = info.renderFrameRate;
outInfo->hasArrSupport = info.hasArrSupport;
+ gui::FrameRateCategoryRate& frameRateCategoryRate = outInfo->frameRateCategoryRate;
+ frameRateCategoryRate.normal = info.frameRateCategoryRate.getNormal();
+ frameRateCategoryRate.high = info.frameRateCategoryRate.getHigh();
outInfo->supportedColorModes.clear();
outInfo->supportedColorModes.reserve(info.supportedColorModes.size());
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index db0e15e..c21df19 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -851,13 +851,14 @@
void attachReleaseFenceFutureToLayer(Layer* layer, LayerFE* layerFE, ui::LayerStack layerStack);
// Checks if a protected layer exists in a list of layers.
- bool layersHasProtectedLayer(const std::vector<sp<LayerFE>>& layers) const;
+ bool layersHasProtectedLayer(const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) const;
using OutputCompositionState = compositionengine::impl::OutputCompositionState;
std::optional<OutputCompositionState> getSnapshotsFromMainThread(
RenderAreaBuilderVariant& renderAreaBuilder,
- GetLayerSnapshotsFunction getLayerSnapshotsFn, std::vector<sp<LayerFE>>& layerFEs);
+ GetLayerSnapshotsFunction getLayerSnapshotsFn,
+ std::vector<std::pair<Layer*, sp<LayerFE>>>& layers);
void captureScreenCommon(RenderAreaBuilderVariant, GetLayerSnapshotsFunction,
ui::Size bufferSize, ui::PixelFormat, bool allowProtected,
@@ -866,32 +867,19 @@
std::optional<OutputCompositionState> getDisplayStateFromRenderAreaBuilder(
RenderAreaBuilderVariant& renderAreaBuilder) REQUIRES(kMainThreadContext);
- // Legacy layer raw pointer is not safe to access outside the main thread.
- // Creates a new vector consisting only of LayerFEs, which can be safely
- // accessed outside the main thread.
- std::vector<sp<LayerFE>> extractLayerFEs(
- const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) const;
-
ftl::SharedFuture<FenceResult> captureScreenshot(
const RenderAreaBuilderVariant& renderAreaBuilder,
const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling,
bool grayscale, bool isProtected, bool attachGainmap,
const sp<IScreenCaptureListener>& captureListener,
std::optional<OutputCompositionState>& displayState,
- std::vector<sp<LayerFE>>& layerFEs);
-
- ftl::SharedFuture<FenceResult> captureScreenshotLegacy(
- RenderAreaBuilderVariant, GetLayerSnapshotsFunction,
- const std::shared_ptr<renderengine::ExternalTexture>&, bool regionSampling,
- bool grayscale, bool isProtected, bool attachGainmap,
- const sp<IScreenCaptureListener>&);
+ std::vector<std::pair<Layer*, sp<LayerFE>>>& layers);
ftl::SharedFuture<FenceResult> renderScreenImpl(
const RenderArea*, const std::shared_ptr<renderengine::ExternalTexture>&,
- bool regionSampling, bool grayscale, bool isProtected, bool attachGainmap,
- ScreenCaptureResults&, std::optional<OutputCompositionState>& displayState,
- std::vector<std::pair<Layer*, sp<LayerFE>>>& layers,
- std::vector<sp<LayerFE>>& layerFEs);
+ bool regionSampling, bool grayscale, bool isProtected, ScreenCaptureResults&,
+ std::optional<OutputCompositionState>& displayState,
+ std::vector<std::pair<Layer*, sp<LayerFE>>>& layers);
void readPersistentProperties();
@@ -1221,6 +1209,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;
@@ -1245,7 +1241,6 @@
// latched.
std::unordered_set<std::pair<sp<Layer>, gui::GameMode>, LayerIntHash> mLayersWithQueuedFrames;
std::unordered_set<sp<Layer>, SpHash<Layer>> mLayersWithBuffersRemoved;
- std::unordered_set<uint32_t> mLayersIdsWithQueuedFrames;
// Sorted list of layers that were composed during previous frame. This is used to
// avoid an expensive traversal of the layer hierarchy when there are no
@@ -1415,6 +1410,11 @@
// Whether a display should be turned on when initialized
bool mSkipPowerOnForQuiescent;
+ // used for omitting vsync callbacks to apps when the display is not updatable
+ int mRefreshableDisplays GUARDED_BY(mStateLock) = 0;
+ void incRefreshableDisplays() REQUIRES(mStateLock);
+ void decRefreshableDisplays() REQUIRES(mStateLock);
+
frontend::LayerLifecycleManager mLayerLifecycleManager GUARDED_BY(kMainThreadContext);
frontend::LayerHierarchyBuilder mLayerHierarchyBuilder GUARDED_BY(kMainThreadContext);
frontend::LayerSnapshotBuilder mLayerSnapshotBuilder GUARDED_BY(kMainThreadContext);
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp
index de4825b..b22ec66 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.cpp
+++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp
@@ -144,7 +144,7 @@
eventStats, handle->previousReleaseCallbackId);
if (handle->bufferReleaseChannel &&
handle->previousReleaseCallbackId != ReleaseCallbackId::INVALID_ID) {
- mBufferReleases.emplace_back(handle->bufferReleaseChannel,
+ mBufferReleases.emplace_back(handle->name, handle->bufferReleaseChannel,
handle->previousReleaseCallbackId,
handle->previousReleaseFence,
handle->currentMaxAcquiredBufferCount);
@@ -159,8 +159,13 @@
void TransactionCallbackInvoker::sendCallbacks(bool onCommitOnly) {
for (const auto& bufferRelease : mBufferReleases) {
- bufferRelease.channel->writeReleaseFence(bufferRelease.callbackId, bufferRelease.fence,
- bufferRelease.currentMaxAcquiredBufferCount);
+ status_t status = bufferRelease.channel
+ ->writeReleaseFence(bufferRelease.callbackId, bufferRelease.fence,
+ bufferRelease.currentMaxAcquiredBufferCount);
+ if (status != OK) {
+ ALOGE("[%s] writeReleaseFence failed. error %d (%s)", bufferRelease.layerName.c_str(),
+ -status, strerror(-status));
+ }
}
mBufferReleases.clear();
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h
index d81d8d0..178ddbb 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.h
+++ b/services/surfaceflinger/TransactionCallbackInvoker.h
@@ -83,6 +83,7 @@
mCompletedTransactions;
struct BufferRelease {
+ std::string layerName;
std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> channel;
ReleaseCallbackId callbackId;
sp<Fence> fence;
diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp
index a331491..57ef4c7 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);
@@ -138,6 +139,7 @@
DUMP_READ_ONLY_FLAG(vrr_bugfix_dropped_frame);
DUMP_READ_ONLY_FLAG(restore_blur_step);
DUMP_READ_ONLY_FLAG(dont_skip_on_early_ro);
+ DUMP_READ_ONLY_FLAG(no_vsyncs_on_screen_off);
DUMP_READ_ONLY_FLAG(protected_if_client);
DUMP_READ_ONLY_FLAG(idle_screen_refresh_rate_timeout);
DUMP_READ_ONLY_FLAG(graphite_renderengine);
@@ -152,9 +154,10 @@
DUMP_READ_ONLY_FLAG(override_trusted_overlay);
DUMP_READ_ONLY_FLAG(flush_buffer_slots_to_uncache);
DUMP_READ_ONLY_FLAG(force_compile_graphite_renderengine);
- 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);
+ DUMP_READ_ONLY_FLAG(connected_display_hdr);
#undef DUMP_READ_ONLY_FLAG
#undef DUMP_SERVER_FLAG
@@ -220,6 +223,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")
@@ -241,6 +245,7 @@
FLAG_MANAGER_READ_ONLY_FLAG(renderable_buffer_usage, "")
FLAG_MANAGER_READ_ONLY_FLAG(restore_blur_step, "debug.renderengine.restore_blur_step")
FLAG_MANAGER_READ_ONLY_FLAG(dont_skip_on_early_ro, "")
+FLAG_MANAGER_READ_ONLY_FLAG(no_vsyncs_on_screen_off, "debug.sf.no_vsyncs_on_screen_off")
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, "")
@@ -256,8 +261,9 @@
FLAG_MANAGER_READ_ONLY_FLAG(override_trusted_overlay, "");
FLAG_MANAGER_READ_ONLY_FLAG(flush_buffer_slots_to_uncache, "");
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, "");
+FLAG_MANAGER_READ_ONLY_FLAG(connected_display_hdr, "");
/// 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 daaf338..7716762 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;
@@ -76,6 +77,7 @@
bool renderable_buffer_usage() const;
bool restore_blur_step() const;
bool dont_skip_on_early_ro() const;
+ bool no_vsyncs_on_screen_off() const;
bool protected_if_client() const;
bool idle_screen_refresh_rate_timeout() const;
bool graphite_renderengine() const;
@@ -90,9 +92,10 @@
bool override_trusted_overlay() const;
bool flush_buffer_slots_to_uncache() const;
bool force_compile_graphite_renderengine() const;
- bool single_hop_screenshot() const;
bool trace_frame_rate_override() const;
bool true_hdr_screenshots() const;
+ bool display_config_error_hal() const;
+ bool connected_display_hdr() const;
protected:
// overridden for unit tests
diff --git a/services/surfaceflinger/fuzzer/Android.bp b/services/surfaceflinger/fuzzer/Android.bp
index ae502cf..1de6b4a 100644
--- a/services/surfaceflinger/fuzzer/Android.bp
+++ b/services/surfaceflinger/fuzzer/Android.bp
@@ -28,16 +28,18 @@
cc_defaults {
name: "surfaceflinger_fuzz_defaults",
static_libs: [
- "libc++fs",
"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..ce334e4 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"
@@ -13,12 +21,20 @@
flag {
name: "arr_setframerate_api"
namespace: "core_graphics"
- description: "New setFrameRate API for Android 16"
+ description: "New SDK Surface#setFrameRate API and Surface.FrameRateParams for Android 16"
bug: "356987016"
is_fixed_read_only: true
} # arr_setframerate_api
flag {
+ name: "arr_surfacecontrol_setframerate_api"
+ namespace: "core_graphics"
+ description: "New SDK SurfaceControl.Transaction#setFrameRate API for Android 16"
+ bug: "356987016"
+ is_fixed_read_only: true
+} # arr_surfacecontrol_setframerate_api
+
+flag {
name: "ce_fence_promise"
namespace: "window_surfaces"
description: "Moves logic for buffer release fences into LayerFE"
@@ -41,6 +57,14 @@
} # commit_not_composited
flag {
+ name: "connected_display_hdr"
+ namespace: "core_graphics"
+ description: "enable connected display hdr capability"
+ bug: "374182788"
+ is_fixed_read_only: true
+} # connected_display_hdr
+
+flag {
name: "correct_dpi_with_display_size"
namespace: "core_graphics"
description: "indicate whether missing or likely incorrect dpi should be corrected using the display size."
@@ -74,6 +98,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"
@@ -134,6 +166,14 @@
} # local_tonemap_screenshots
flag {
+ name: "no_vsyncs_on_screen_off"
+ namespace: "core_graphics"
+ description: "Stop vsync / Choreographer callbacks to apps when the screen is off"
+ bug: "331636736"
+ is_fixed_read_only: true
+} # no_vsyncs_on_screen_off
+
+flag {
name: "single_hop_screenshot"
namespace: "window_surfaces"
description: "Only access SF main thread once during a screenshot"
diff --git a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
index b472047..9794620 100644
--- a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
+++ b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
@@ -218,6 +218,17 @@
mLifecycleManager.applyTransactions(transactions);
}
+ void setAutoRefresh(uint32_t id, bool autoRefresh) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eAutoRefreshChanged;
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().state.autoRefresh = autoRefresh;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
void hideLayer(uint32_t id) {
setFlags(id, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden);
}
diff --git a/services/surfaceflinger/tests/tracing/Android.bp b/services/surfaceflinger/tests/tracing/Android.bp
index bce1406..6eb7f4a 100644
--- a/services/surfaceflinger/tests/tracing/Android.bp
+++ b/services/surfaceflinger/tests/tracing/Android.bp
@@ -35,9 +35,6 @@
":libsurfaceflinger_mock_sources",
"TransactionTraceTestSuite.cpp",
],
- static_libs: [
- "libc++fs",
- ],
header_libs: [
"libsurfaceflinger_mocks_headers",
],
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index f1bd87c..cb8820a 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",
],
}
@@ -57,9 +81,9 @@
"surfaceflinger_defaults",
],
test_suites: ["device-tests"],
- 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 +223,7 @@
"libpowermanager",
"libprocessgroup",
"libprotobuf-cpp-lite",
+ "libstatslog_surfaceflinger",
"libSurfaceFlingerProp",
"libsync",
"libui",
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index a35ae15..e6b8a26 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -1935,4 +1935,54 @@
EXPECT_FALSE(getSnapshot(2)->hasInputInfo());
}
+// content dirty test
+TEST_F(LayerSnapshotTest, contentDirtyWhenParentAlphaChanges) {
+ setAlpha(1, 0.5);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_TRUE(getSnapshot(1)->contentDirty);
+ EXPECT_TRUE(getSnapshot(11)->contentDirty);
+ EXPECT_TRUE(getSnapshot(111)->contentDirty);
+
+ // subsequent updates clear the dirty bit
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_FALSE(getSnapshot(1)->contentDirty);
+ EXPECT_FALSE(getSnapshot(11)->contentDirty);
+ EXPECT_FALSE(getSnapshot(111)->contentDirty);
+}
+
+TEST_F(LayerSnapshotTest, contentDirtyWhenAutoRefresh) {
+ setAutoRefresh(1, true);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_TRUE(getSnapshot(1)->contentDirty);
+
+ // subsequent updates don't clear the dirty bit
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_TRUE(getSnapshot(1)->contentDirty);
+
+ // second update after removing auto refresh will clear content dirty
+ setAutoRefresh(1, false);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_FALSE(getSnapshot(1)->contentDirty);
+}
+
+TEST_F(LayerSnapshotTest, contentDirtyWhenColorChanges) {
+ setColor(1, {1, 2, 3});
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_TRUE(getSnapshot(1)->contentDirty);
+
+ // subsequent updates clear the dirty bit
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_FALSE(getSnapshot(1)->contentDirty);
+}
+
+TEST_F(LayerSnapshotTest, contentDirtyWhenParentGeometryChanges) {
+ setPosition(1, 2, 3);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_TRUE(getSnapshot(1)->contentDirty);
+
+ // subsequent updates clear the dirty bit
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_FALSE(getSnapshot(1)->contentDirty);
+}
} // namespace android::surfaceflinger::frontend
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/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 4dec5f6..6778af3 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -472,12 +472,10 @@
ScreenCaptureResults captureResults;
auto displayState = std::optional{display->getCompositionDisplay()->getState()};
auto layers = getLayerSnapshotsFn();
- auto layerFEs = mFlinger->extractLayerFEs(layers);
return mFlinger->renderScreenImpl(renderArea.get(), buffer, regionSampling,
false /* grayscale */, false /* isProtected */,
- false /* attachGainmap */, captureResults, displayState,
- layers, layerFEs);
+ captureResults, displayState, layers);
}
auto getLayerSnapshotsForScreenshotsFn(ui::LayerStack layerStack, uint32_t uid) {
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/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.h
index ed1405b..4c034d7 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.h
@@ -32,6 +32,7 @@
using aidl::android::hardware::power::IPowerHintSession;
using aidl::android::hardware::power::SessionConfig;
using aidl::android::hardware::power::SessionTag;
+using aidl::android::hardware::power::SupportInfo;
using aidl::android::hardware::power::Mode;
using android::binder::Status;
@@ -59,6 +60,7 @@
MOCK_METHOD(ndk::ScopedAStatus, getSessionChannel,
(int32_t tgid, int32_t uid, ChannelConfig* _aidl_return), (override));
MOCK_METHOD(ndk::ScopedAStatus, closeSessionChannel, (int32_t tgid, int32_t uid), (override));
+ MOCK_METHOD(ndk::ScopedAStatus, getSupportInfo, (SupportInfo * _aidl_return), (override));
MOCK_METHOD(ndk::ScopedAStatus, getInterfaceVersion, (int32_t * version), (override));
MOCK_METHOD(ndk::ScopedAStatus, getInterfaceHash, (std::string * hash), (override));
MOCK_METHOD(ndk::SpAIBinder, asBinder, (), (override));
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index 7398cbe..82500fe 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -30,6 +30,7 @@
MOCK_METHOD(sp<EventThreadConnection>, createEventConnection, (EventRegistrationFlags),
(const, override));
MOCK_METHOD(void, enableSyntheticVsync, (bool), (override));
+ MOCK_METHOD(void, omitVsyncDispatching, (bool), (override));
MOCK_METHOD(void, onHotplugReceived, (PhysicalDisplayId, bool), (override));
MOCK_METHOD(void, onHotplugConnectionError, (int32_t), (override));
MOCK_METHOD(void, onModeChanged, (const scheduler::FrameRateMode&), (override));
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));