Merge "RESTRICT AUTOMERGE Ignore weak symbol difference in libbinder ABI check" into tm-dev
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index b4aa88e..a49f563 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -1957,17 +1957,43 @@
#endif // GRANULAR_LOCKS
FTS *fts;
FTSENT *p;
+
+ // Create a list of data paths whose children have cache directories
auto ce_path = create_data_user_ce_path(uuid_, userId);
auto de_path = create_data_user_de_path(uuid_, userId);
auto media_path = findDataMediaPath(uuid, userId) + "/Android/data/";
- char *argv[] = { (char*) ce_path.c_str(), (char*) de_path.c_str(),
- (char*) media_path.c_str(), nullptr };
+ auto ce_sdk_path = create_data_misc_sdk_sandbox_path(uuid_, /*isCeData=*/true, userId);
+ auto de_sdk_path = create_data_misc_sdk_sandbox_path(uuid_, /*isCeData=*/false, userId);
+
+ std::vector<std::string> dataPaths = {ce_path, de_path, media_path};
+ foreach_subdir(ce_sdk_path, [&ce_sdk_path, &dataPaths](const std::string subDir) {
+ const auto fullpath = ce_sdk_path + "/" + subDir;
+ dataPaths.push_back(fullpath);
+ });
+ foreach_subdir(de_sdk_path, [&de_sdk_path, &dataPaths](const std::string subDir) {
+ const auto fullpath = de_sdk_path + "/" + subDir;
+ dataPaths.push_back((char*)fullpath.c_str());
+ });
+
+ char* argv[dataPaths.size() + 1];
+ for (unsigned int i = 0; i < dataPaths.size(); i++) {
+ argv[i] = (char*)dataPaths[i].c_str();
+ }
+ argv[dataPaths.size()] = nullptr;
+
if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
return error("Failed to fts_open");
}
while ((p = fts_read(fts)) != nullptr) {
if (p->fts_info == FTS_D && p->fts_level == 1) {
uid_t uid = p->fts_statp->st_uid;
+
+ // If uid belongs to sdk sandbox, then the cache should be attributed to the
+ // original client app.
+ const auto client_uid = multiuser_convert_sdk_sandbox_to_app_uid(uid);
+ const bool isSandboxUid = (client_uid != (uid_t)-1);
+ if (isSandboxUid) uid = client_uid;
+
if (multiuser_get_app_id(uid) == AID_MEDIA_RW) {
uid = (multiuser_get_app_id(p->fts_statp->st_gid) - AID_EXT_GID_START)
+ AID_APP_START;
diff --git a/include/android/sensor.h b/include/android/sensor.h
index 6112d5f..eef69f4 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -267,7 +267,8 @@
* {@link ASENSOR_TYPE_HEAD_TRACKER}
* reporting-mode: continuous
*
- * Measures the orientation and rotational velocity of a user's head.
+ * Measures the orientation and rotational velocity of a user's head. Only for internal use
+ * within the Android system.
*/
ASENSOR_TYPE_HEAD_TRACKER = 37,
/**
diff --git a/include/ftl/details/future.h b/include/ftl/details/future.h
new file mode 100644
index 0000000..df1323e
--- /dev/null
+++ b/include/ftl/details/future.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+namespace android::ftl {
+
+template <typename, template <typename> class>
+class Future;
+
+namespace details {
+
+template <typename T>
+struct future_result {
+ using type = T;
+};
+
+template <typename T>
+struct future_result<std::future<T>> {
+ using type = T;
+};
+
+template <typename T>
+struct future_result<std::shared_future<T>> {
+ using type = T;
+};
+
+template <typename T, template <typename> class FutureImpl>
+struct future_result<Future<T, FutureImpl>> {
+ using type = T;
+};
+
+template <typename T>
+using future_result_t = typename future_result<T>::type;
+
+struct ValueTag {};
+
+template <typename, typename T, template <typename> class>
+class BaseFuture;
+
+template <typename Self, typename T>
+class BaseFuture<Self, T, std::future> {
+ using Impl = std::future<T>;
+
+ public:
+ Future<T, std::shared_future> share() {
+ if (T* value = std::get_if<T>(&self())) {
+ return {ValueTag{}, std::move(*value)};
+ }
+
+ return std::get<Impl>(self()).share();
+ }
+
+ protected:
+ T get() {
+ if (T* value = std::get_if<T>(&self())) {
+ return std::move(*value);
+ }
+
+ return std::get<Impl>(self()).get();
+ }
+
+ private:
+ auto& self() { return static_cast<Self&>(*this).future_; }
+};
+
+template <typename Self, typename T>
+class BaseFuture<Self, T, std::shared_future> {
+ using Impl = std::shared_future<T>;
+
+ protected:
+ const T& get() const {
+ if (const T* value = std::get_if<T>(&self())) {
+ return *value;
+ }
+
+ return std::get<Impl>(self()).get();
+ }
+
+ private:
+ const auto& self() const { return static_cast<const Self&>(*this).future_; }
+};
+
+} // namespace details
+} // namespace android::ftl
diff --git a/include/ftl/future.h b/include/ftl/future.h
index dd6358f..c78f9b7 100644
--- a/include/ftl/future.h
+++ b/include/ftl/future.h
@@ -19,18 +19,87 @@
#include <future>
#include <type_traits>
#include <utility>
+#include <variant>
+
+#include <ftl/details/future.h>
namespace android::ftl {
-// Creates a future that defers a function call until its result is queried.
+// Thin wrapper around FutureImpl<T> (concretely std::future<T> or std::shared_future<T>) with
+// extensions for pure values (created via ftl::yield) and continuations.
//
-// auto future = ftl::defer([](int x) { return x + 1; }, 99);
-// assert(future.get() == 100);
+// See also SharedFuture<T> shorthand below.
//
-template <typename F, typename... Args>
-inline auto defer(F&& f, Args&&... args) {
- return std::async(std::launch::deferred, std::forward<F>(f), std::forward<Args>(args)...);
-}
+template <typename T, template <typename> class FutureImpl = std::future>
+class Future final : public details::BaseFuture<Future<T, FutureImpl>, T, FutureImpl> {
+ using Base = details::BaseFuture<Future, T, FutureImpl>;
+
+ friend Base; // For BaseFuture<...>::self.
+ friend details::BaseFuture<Future<T>, T, std::future>; // For BaseFuture<...>::share.
+
+ public:
+ // Constructs an invalid future.
+ Future() : future_(std::in_place_type<FutureImpl<T>>) {}
+
+ // Constructs a future from its standard counterpart, implicitly.
+ Future(FutureImpl<T>&& f) : future_(std::move(f)) {}
+
+ bool valid() const {
+ return std::holds_alternative<T>(future_) || std::get<FutureImpl<T>>(future_).valid();
+ }
+
+ // Forwarding functions. Base::share is only defined when FutureImpl is std::future, whereas the
+ // following are defined for either FutureImpl:
+ using Base::get;
+
+ // Attaches a continuation to the future. The continuation is a function that maps T to either R
+ // or ftl::Future<R>. In the former case, the chain wraps the result in a future as if by
+ // ftl::yield.
+ //
+ // auto future = ftl::yield(123);
+ // ftl::Future<char> futures[] = {ftl::yield('a'), ftl::yield('b')};
+ //
+ // auto chain =
+ // ftl::Future(std::move(future))
+ // .then([](int x) { return static_cast<std::size_t>(x % 2); })
+ // .then([&futures](std::size_t i) { return std::move(futures[i]); });
+ //
+ // assert(chain.get() == 'b');
+ //
+ template <typename F, typename R = std::invoke_result_t<F, T>>
+ auto then(F&& op) && -> Future<details::future_result_t<R>> {
+ return defer(
+ [](auto&& f, F&& op) {
+ R r = op(f.get());
+ if constexpr (std::is_same_v<R, details::future_result_t<R>>) {
+ return r;
+ } else {
+ return r.get();
+ }
+ },
+ std::move(*this), std::forward<F>(op));
+ }
+
+ private:
+ template <typename V>
+ friend Future<V> yield(V&&);
+
+ template <typename V, typename... Args>
+ friend Future<V> yield(Args&&...);
+
+ template <typename... Args>
+ Future(details::ValueTag, Args&&... args)
+ : future_(std::in_place_type<T>, std::forward<Args>(args)...) {}
+
+ std::variant<T, FutureImpl<T>> future_;
+};
+
+template <typename T>
+using SharedFuture = Future<T, std::shared_future>;
+
+// Deduction guide for implicit conversion.
+template <typename T, template <typename> class FutureImpl>
+Future(FutureImpl<T>&&) -> Future<T, FutureImpl>;
// Creates a future that wraps a value.
//
@@ -41,69 +110,24 @@
// auto future = ftl::yield(std::move(ptr));
// assert(*future.get() == '!');
//
-template <typename T>
-inline std::future<T> yield(T&& v) {
- return defer([](T&& v) { return std::forward<T>(v); }, std::forward<T>(v));
+template <typename V>
+inline Future<V> yield(V&& value) {
+ return {details::ValueTag{}, std::move(value)};
}
-namespace details {
+template <typename V, typename... Args>
+inline Future<V> yield(Args&&... args) {
+ return {details::ValueTag{}, std::forward<Args>(args)...};
+}
-template <typename T>
-struct future_result {
- using type = T;
-};
-
-template <typename T>
-struct future_result<std::future<T>> {
- using type = T;
-};
-
-template <typename T>
-using future_result_t = typename future_result<T>::type;
-
-// Attaches a continuation to a future. The continuation is a function that maps T to either R or
-// std::future<R>. In the former case, the chain wraps the result in a future as if by ftl::yield.
+// Creates a future that defers a function call until its result is queried.
//
-// auto future = ftl::yield(123);
-// std::future<char> futures[] = {ftl::yield('a'), ftl::yield('b')};
+// auto future = ftl::defer([](int x) { return x + 1; }, 99);
+// assert(future.get() == 100);
//
-// std::future<char> chain =
-// ftl::chain(std::move(future))
-// .then([](int x) { return static_cast<std::size_t>(x % 2); })
-// .then([&futures](std::size_t i) { return std::move(futures[i]); });
-//
-// assert(chain.get() == 'b');
-//
-template <typename T>
-struct Chain {
- // Implicit conversion.
- Chain(std::future<T>&& f) : future(std::move(f)) {}
- operator std::future<T>&&() && { return std::move(future); }
-
- T get() && { return future.get(); }
-
- template <typename F, typename R = std::invoke_result_t<F, T>>
- auto then(F&& op) && -> Chain<future_result_t<R>> {
- return defer(
- [](auto&& f, F&& op) {
- R r = op(f.get());
- if constexpr (std::is_same_v<R, future_result_t<R>>) {
- return r;
- } else {
- return r.get();
- }
- },
- std::move(future), std::forward<F>(op));
- }
-
- std::future<T> future;
-};
-
-} // namespace details
-
-template <typename T>
-inline auto chain(std::future<T>&& f) -> details::Chain<T> {
- return std::move(f);
+template <typename F, typename... Args>
+inline auto defer(F&& f, Args&&... args) {
+ return Future(std::async(std::launch::deferred, std::forward<F>(f), std::forward<Args>(args)...));
}
} // namespace android::ftl
diff --git a/include/input/PrintTools.h b/include/input/PrintTools.h
index 7c3b29b..0a75278 100644
--- a/include/input/PrintTools.h
+++ b/include/input/PrintTools.h
@@ -58,4 +58,13 @@
const char* toString(bool value);
+/**
+ * Add "prefix" to the beginning of each line in the provided string
+ * "str".
+ * The string 'str' is typically multi-line.
+ * The most common use case for this function is to add some padding
+ * when dumping state.
+ */
+std::string addLinePrefix(std::string str, const std::string& prefix);
+
} // namespace android
\ No newline at end of file
diff --git a/libs/ftl/future_test.cpp b/libs/ftl/future_test.cpp
index 9b3e936..5a245b6 100644
--- a/libs/ftl/future_test.cpp
+++ b/libs/ftl/future_test.cpp
@@ -42,9 +42,9 @@
}
{
auto future = ftl::yield(123);
- std::future<char> futures[] = {ftl::yield('a'), ftl::yield('b')};
+ ftl::Future<char> futures[] = {ftl::yield('a'), ftl::yield('b')};
- std::future<char> chain = ftl::chain(std::move(future))
+ ftl::Future<char> chain = ftl::Future(std::move(future))
.then([](int x) { return static_cast<size_t>(x % 2); })
.then([&futures](size_t i) { return std::move(futures[i]); });
@@ -71,7 +71,7 @@
return ByteVector{str.begin(), str.end()};
});
- std::packaged_task<std::future<ByteVector>(ByteVector)> decrement_bytes(
+ std::packaged_task<ftl::Future<ByteVector>(ByteVector)> decrement_bytes(
[](ByteVector bytes) { return ftl::defer(decrement, std::move(bytes)); });
auto fetch = fetch_string.get_future();
@@ -81,7 +81,7 @@
EXPECT_EQ(
"hello, world",
- ftl::chain(std::move(fetch))
+ ftl::Future(std::move(fetch))
.then([](const char* str) { return std::string(str); })
.then([&](std::string str) {
auto append = append_string.get_future();
@@ -93,7 +93,7 @@
decrement_thread = std::thread(std::move(decrement_bytes), std::move(bytes));
return decrement;
})
- .then([](std::future<ByteVector> bytes) { return bytes; })
+ .then([](ftl::Future<ByteVector> bytes) { return bytes; })
.then([](const ByteVector& bytes) { return std::string(bytes.begin(), bytes.end()); })
.get());
diff --git a/libs/gralloc/types/Gralloc4.cpp b/libs/gralloc/types/Gralloc4.cpp
index 68b99b0..61e6657 100644
--- a/libs/gralloc/types/Gralloc4.cpp
+++ b/libs/gralloc/types/Gralloc4.cpp
@@ -196,35 +196,6 @@
status_t validateMetadataType(InputHidlVec* input, const MetadataType& expectedMetadataType);
/**
- * Private helper functions
- */
-template <class T>
-status_t encodeInteger(const T& input, OutputHidlVec* output) {
- static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
- std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
- std::is_same<T, float>::value || std::is_same<T, double>::value);
- if (!output) {
- return BAD_VALUE;
- }
-
- const uint8_t* tmp = reinterpret_cast<const uint8_t*>(&input);
- return output->encode(tmp, sizeof(input));
-}
-
-template <class T>
-status_t decodeInteger(InputHidlVec* input, T* output) {
- static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
- std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
- std::is_same<T, float>::value || std::is_same<T, double>::value);
- if (!output) {
- return BAD_VALUE;
- }
-
- uint8_t* tmp = reinterpret_cast<uint8_t*>(output);
- return input->decode(tmp, sizeof(*output));
-}
-
-/**
* encode/encodeMetadata are the main encoding functions. They take in T and uses the encodeHelper
* function to turn T into the hidl_vec byte stream.
*
@@ -280,45 +251,10 @@
template <class T>
status_t encodeOptionalMetadata(const MetadataType& metadataType, const std::optional<T>& input,
hidl_vec<uint8_t>* output, EncodeHelper<T> encodeHelper) {
- OutputHidlVec outputHidlVec{output};
-
- status_t err = encodeMetadataType(metadataType, &outputHidlVec);
- if (err) {
- return err;
+ if (!input) {
+ return NO_ERROR;
}
-
- err = encodeInteger<uint32_t>(input.has_value() ? 1 : 0, &outputHidlVec);
- if (err) {
- return err;
- }
-
- if (input) {
- err = encodeHelper(*input, &outputHidlVec);
- if (err) {
- return err;
- }
- }
-
- err = outputHidlVec.resize();
- if (err) {
- return err;
- }
-
- err = encodeMetadataType(metadataType, &outputHidlVec);
- if (err) {
- return err;
- }
-
- err = encodeInteger<uint32_t>(input.has_value() ? 1 : 0, &outputHidlVec);
- if (err) {
- return err;
- }
-
- if (input) {
- return encodeHelper(*input, &outputHidlVec);
- }
-
- return NO_ERROR;
+ return encodeMetadata(metadataType, *input, output, encodeHelper);
}
/**
@@ -379,36 +315,45 @@
if (!output) {
return BAD_VALUE;
}
-
- InputHidlVec inputHidlVec{&input};
-
- status_t err = validateMetadataType(&inputHidlVec, metadataType);
- if (err) {
- return err;
+ if (input.size() <= 0) {
+ output->reset();
+ return NO_ERROR;
}
-
- uint32_t present = 0;
- err = decodeInteger<uint32_t>(&inputHidlVec, &present);
- if (err) {
- return err;
- }
-
- if (present) {
- T tmp;
- err = decodeHelper(&inputHidlVec, &tmp);
- if (err) {
- return err;
- }
-
+ T tmp;
+ status_t err = decodeMetadata(metadataType, input, &tmp, decodeHelper);
+ if (!err) {
*output = tmp;
}
+ return err;
+}
- err = inputHidlVec.hasRemainingData();
- if (err) {
+/**
+ * Private helper functions
+ */
+template <class T>
+status_t encodeInteger(const T& input, OutputHidlVec* output) {
+ static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
+ std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
+ std::is_same<T, float>::value || std::is_same<T, double>::value);
+ if (!output) {
return BAD_VALUE;
}
- return NO_ERROR;
+ const uint8_t* tmp = reinterpret_cast<const uint8_t*>(&input);
+ return output->encode(tmp, sizeof(input));
+}
+
+template <class T>
+status_t decodeInteger(InputHidlVec* input, T* output) {
+ static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
+ std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
+ std::is_same<T, float>::value || std::is_same<T, double>::value);
+ if (!output) {
+ return BAD_VALUE;
+ }
+
+ uint8_t* tmp = reinterpret_cast<uint8_t*>(output);
+ return input->decode(tmp, sizeof(*output));
}
status_t encodeString(const std::string& input, OutputHidlVec* output) {
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 501f8cf..47d801a 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1497,6 +1497,13 @@
releaseBufferIfOverwriting(*s);
+ if (buffer == nullptr) {
+ s->what &= ~layer_state_t::eBufferChanged;
+ s->bufferData = nullptr;
+ mContainsBuffer = false;
+ return *this;
+ }
+
std::shared_ptr<BufferData> bufferData = std::make_shared<BufferData>();
bufferData->buffer = buffer;
uint64_t frameNumber = sc->resolveFrameNumber(optFrameNumber);
diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp
index 804ce4f..4e966d1 100644
--- a/libs/gui/WindowInfo.cpp
+++ b/libs/gui/WindowInfo.cpp
@@ -76,7 +76,7 @@
info.inputConfig == inputConfig && info.displayId == displayId &&
info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop &&
info.applicationInfo == applicationInfo && info.layoutParamsType == layoutParamsType &&
- info.layoutParamsFlags == layoutParamsFlags;
+ info.layoutParamsFlags == layoutParamsFlags && info.isClone == isClone;
}
status_t WindowInfo::writeToParcel(android::Parcel* parcel) const {
@@ -124,7 +124,8 @@
parcel->write(touchableRegion) ?:
parcel->writeBool(replaceTouchableRegionWithCrop) ?:
parcel->writeStrongBinder(touchableRegionCropHandle.promote()) ?:
- parcel->writeStrongBinder(windowToken);
+ parcel->writeStrongBinder(windowToken) ?:
+ parcel->writeBool(isClone);
// clang-format on
return status;
}
@@ -175,7 +176,8 @@
parcel->read(touchableRegion) ?:
parcel->readBool(&replaceTouchableRegionWithCrop) ?:
parcel->readNullableStrongBinder(&touchableRegionCropHandleSp) ?:
- parcel->readNullableStrongBinder(&windowToken);
+ parcel->readNullableStrongBinder(&windowToken) ?:
+ parcel->readBool(&isClone);
// clang-format on
if (status != OK) {
diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h
index 0e1d258..169f7f0 100644
--- a/libs/gui/include/gui/WindowInfo.h
+++ b/libs/gui/include/gui/WindowInfo.h
@@ -236,6 +236,8 @@
void setInputConfig(ftl::Flags<InputConfig> config, bool value);
+ bool isClone = false;
+
void addTouchableRegion(const Rect& region);
bool touchableRegionContainsPoint(int32_t x, int32_t y) const;
diff --git a/libs/gui/tests/WindowInfo_test.cpp b/libs/gui/tests/WindowInfo_test.cpp
index c51b244..99658cc 100644
--- a/libs/gui/tests/WindowInfo_test.cpp
+++ b/libs/gui/tests/WindowInfo_test.cpp
@@ -71,6 +71,7 @@
i.applicationInfo.name = "ApplicationFooBar";
i.applicationInfo.token = new BBinder();
i.applicationInfo.dispatchingTimeoutMillis = 0x12345678ABCD;
+ i.isClone = true;
Parcel p;
i.writeToParcel(&p);
@@ -101,6 +102,7 @@
ASSERT_EQ(i.replaceTouchableRegionWithCrop, i2.replaceTouchableRegionWithCrop);
ASSERT_EQ(i.touchableRegionCropHandle, i2.touchableRegionCropHandle);
ASSERT_EQ(i.applicationInfo, i2.applicationInfo);
+ ASSERT_EQ(i.isClone, i2.isClone);
}
TEST(InputApplicationInfo, Parcelling) {
diff --git a/libs/input/PrintTools.cpp b/libs/input/PrintTools.cpp
index 5d6ae4e..01f6bf5 100644
--- a/libs/input/PrintTools.cpp
+++ b/libs/input/PrintTools.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "PrintTools"
#include <input/PrintTools.h>
+#include <sstream>
namespace android {
@@ -24,4 +25,20 @@
return value ? "true" : "false";
}
+std::string addLinePrefix(std::string str, const std::string& prefix) {
+ std::stringstream ss;
+ bool newLineStarted = true;
+ for (const auto& ch : str) {
+ if (newLineStarted) {
+ ss << prefix;
+ newLineStarted = false;
+ }
+ if (ch == '\n') {
+ newLineStarted = true;
+ }
+ ss << ch;
+ }
+ return ss.str();
+}
+
} // namespace android
diff --git a/libs/input/android/os/InputEventInjectionResult.aidl b/libs/input/android/os/InputEventInjectionResult.aidl
index 34f10ec..3bc7068 100644
--- a/libs/input/android/os/InputEventInjectionResult.aidl
+++ b/libs/input/android/os/InputEventInjectionResult.aidl
@@ -29,9 +29,8 @@
/* Injection succeeded. */
SUCCEEDED = 0,
- /* Injection failed because the injector did not have permission to inject
- * into the application with input focus. */
- PERMISSION_DENIED = 1,
+ /* Injection failed because the injected event did not target the appropriate window. */
+ TARGET_MISMATCH = 1,
/* Injection failed because there were no available input targets. */
FAILED = 2,
diff --git a/libs/shaders/shaders.cpp b/libs/shaders/shaders.cpp
index f0d45c2..62745dc 100644
--- a/libs/shaders/shaders.cpp
+++ b/libs/shaders/shaders.cpp
@@ -78,7 +78,7 @@
shader.append(R"(
float EOTF_sRGB(float srgb) {
- return srgb <= 0.08125 ? srgb / 4.50 : pow((srgb + 0.099) / 1.099, 0.45);
+ return srgb <= 0.08125 ? srgb / 4.50 : pow((srgb + 0.099) / 1.099, 1 / 0.45);
}
float3 EOTF_sRGB(float3 srgb) {
diff --git a/services/gpuservice/gpuwork/bpfprogs/gpu_work.c b/services/gpuservice/gpuwork/bpfprogs/gpu_work.c
index 95cfae7..d73fff4 100644
--- a/services/gpuservice/gpuwork/bpfprogs/gpu_work.c
+++ b/services/gpuservice/gpuwork/bpfprogs/gpu_work.c
@@ -153,11 +153,11 @@
uint32_t uid;
// The start time of the period in nanoseconds. The clock must be
- // CLOCK_MONOTONIC, as returned by the ktime_get_ns(void) function.
+ // CLOCK_MONOTONIC_RAW, as returned by the ktime_get_raw_ns(void) function.
uint64_t start_time_ns;
// The end time of the period in nanoseconds. The clock must be
- // CLOCK_MONOTONIC, as returned by the ktime_get_ns(void) function.
+ // CLOCK_MONOTONIC_RAW, as returned by the ktime_get_raw_ns(void) function.
uint64_t end_time_ns;
// The amount of time the GPU was running GPU work for |uid| during the
diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp
index 3ea0986..8ce2f35 100644
--- a/services/inputflinger/InputClassifier.cpp
+++ b/services/inputflinger/InputClassifier.cpp
@@ -367,7 +367,7 @@
// --- InputClassifier ---
-InputClassifier::InputClassifier(InputListenerInterface& listener) : mListener(listener) {}
+InputClassifier::InputClassifier(InputListenerInterface& listener) : mQueuedListener(listener) {}
void InputClassifier::onBinderDied(void* cookie) {
InputClassifier* classifier = static_cast<InputClassifier*>(cookie);
@@ -417,55 +417,67 @@
void InputClassifier::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) {
// pass through
- mListener.notifyConfigurationChanged(args);
+ mQueuedListener.notifyConfigurationChanged(args);
+ mQueuedListener.flush();
}
void InputClassifier::notifyKey(const NotifyKeyArgs* args) {
// pass through
- mListener.notifyKey(args);
+ mQueuedListener.notifyKey(args);
+ mQueuedListener.flush();
}
void InputClassifier::notifyMotion(const NotifyMotionArgs* args) {
- std::scoped_lock lock(mLock);
- // MotionClassifier is only used for touch events, for now
- const bool sendToMotionClassifier = mMotionClassifier && isTouchEvent(*args);
- if (!sendToMotionClassifier) {
- mListener.notifyMotion(args);
- return;
- }
-
- NotifyMotionArgs newArgs(*args);
- newArgs.classification = mMotionClassifier->classify(newArgs);
- mListener.notifyMotion(&newArgs);
+ { // acquire lock
+ std::scoped_lock lock(mLock);
+ // MotionClassifier is only used for touch events, for now
+ const bool sendToMotionClassifier = mMotionClassifier && isTouchEvent(*args);
+ if (!sendToMotionClassifier) {
+ mQueuedListener.notifyMotion(args);
+ } else {
+ NotifyMotionArgs newArgs(*args);
+ newArgs.classification = mMotionClassifier->classify(newArgs);
+ mQueuedListener.notifyMotion(&newArgs);
+ }
+ } // release lock
+ mQueuedListener.flush();
}
void InputClassifier::notifySensor(const NotifySensorArgs* args) {
// pass through
- mListener.notifySensor(args);
+ mQueuedListener.notifySensor(args);
+ mQueuedListener.flush();
}
void InputClassifier::notifyVibratorState(const NotifyVibratorStateArgs* args) {
// pass through
- mListener.notifyVibratorState(args);
+ mQueuedListener.notifyVibratorState(args);
+ mQueuedListener.flush();
}
void InputClassifier::notifySwitch(const NotifySwitchArgs* args) {
// pass through
- mListener.notifySwitch(args);
+ mQueuedListener.notifySwitch(args);
+ mQueuedListener.flush();
}
void InputClassifier::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
- std::scoped_lock lock(mLock);
- if (mMotionClassifier) {
- mMotionClassifier->reset(*args);
- }
+ { // acquire lock
+ std::scoped_lock lock(mLock);
+ if (mMotionClassifier) {
+ mMotionClassifier->reset(*args);
+ }
+ } // release lock
+
// continue to next stage
- mListener.notifyDeviceReset(args);
+ mQueuedListener.notifyDeviceReset(args);
+ mQueuedListener.flush();
}
void InputClassifier::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) {
// pass through
- mListener.notifyPointerCaptureChanged(args);
+ mQueuedListener.notifyPointerCaptureChanged(args);
+ mQueuedListener.flush();
}
void InputClassifier::setMotionClassifierLocked(
@@ -490,6 +502,10 @@
dump += "\n";
}
+void InputClassifier::monitor() {
+ std::scoped_lock lock(mLock);
+}
+
InputClassifier::~InputClassifier() {
}
diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h
index e2a0bc2..56cf760 100644
--- a/services/inputflinger/InputClassifier.h
+++ b/services/inputflinger/InputClassifier.h
@@ -96,6 +96,9 @@
*/
virtual void dump(std::string& dump) = 0;
+ /* Called by the heatbeat to ensures that the classifier has not deadlocked. */
+ virtual void monitor() = 0;
+
InputClassifierInterface() { }
virtual ~InputClassifierInterface() { }
};
@@ -247,6 +250,7 @@
void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
void dump(std::string& dump) override;
+ void monitor() override;
~InputClassifier();
@@ -257,7 +261,7 @@
// Protect access to mMotionClassifier, since it may become null via a hidl callback
std::mutex mLock;
// The next stage to pass input events to
- InputListenerInterface& mListener;
+ QueuedInputListener mQueuedListener;
std::unique_ptr<MotionClassifierInterface> mMotionClassifier GUARDED_BY(mLock);
std::future<void> mInitializeMotionClassifier GUARDED_BY(mLock);
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 7b03631..9767cd9 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -62,8 +62,8 @@
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
mDispatcher = createInputDispatcher(dispatcherPolicy);
mClassifier = std::make_unique<InputClassifier>(*mDispatcher);
- mUnwantedInteractionBlocker = std::make_unique<UnwantedInteractionBlocker>(*mClassifier);
- mReader = createInputReader(readerPolicy, *mUnwantedInteractionBlocker);
+ mBlocker = std::make_unique<UnwantedInteractionBlocker>(*mClassifier);
+ mReader = createInputReader(readerPolicy, *mBlocker);
}
InputManager::~InputManager() {
@@ -111,7 +111,7 @@
}
UnwantedInteractionBlockerInterface& InputManager::getUnwantedInteractionBlocker() {
- return *mUnwantedInteractionBlocker;
+ return *mBlocker;
}
InputClassifierInterface& InputManager::getClassifier() {
@@ -122,6 +122,13 @@
return *mDispatcher;
}
+void InputManager::monitor() {
+ mReader->monitor();
+ mBlocker->monitor();
+ mClassifier->monitor();
+ mDispatcher->monitor();
+}
+
// Used by tests only.
binder::Status InputManager::createInputChannel(const std::string& name, InputChannel* outChannel) {
IPCThreadState* ipc = IPCThreadState::self();
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index 35d2b0f..8aad35b 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -90,6 +90,9 @@
/* Gets the input dispatcher. */
virtual InputDispatcherInterface& getDispatcher() = 0;
+
+ /* Check that the input stages have not deadlocked. */
+ virtual void monitor() = 0;
};
class InputManager : public InputManagerInterface, public BnInputFlinger {
@@ -108,6 +111,7 @@
UnwantedInteractionBlockerInterface& getUnwantedInteractionBlocker() override;
InputClassifierInterface& getClassifier() override;
InputDispatcherInterface& getDispatcher() override;
+ void monitor() override;
status_t dump(int fd, const Vector<String16>& args) override;
binder::Status createInputChannel(const std::string& name, InputChannel* outChannel) override;
@@ -117,7 +121,7 @@
private:
std::unique_ptr<InputReaderInterface> mReader;
- std::unique_ptr<UnwantedInteractionBlockerInterface> mUnwantedInteractionBlocker;
+ std::unique_ptr<UnwantedInteractionBlockerInterface> mBlocker;
std::unique_ptr<InputClassifierInterface> mClassifier;
diff --git a/services/inputflinger/TEST_MAPPING b/services/inputflinger/TEST_MAPPING
index 9b72ff4..b4b617e 100644
--- a/services/inputflinger/TEST_MAPPING
+++ b/services/inputflinger/TEST_MAPPING
@@ -24,6 +24,14 @@
"name": "libinputservice_test"
},
{
+ "name": "CtsHardwareTestCases",
+ "options": [
+ {
+ "include-filter": "android.hardware.input.cts.tests"
+ }
+ ]
+ },
+ {
"name": "CtsInputTestCases"
},
{
@@ -31,6 +39,7 @@
"options": [
{
"include-filter": "android.view.cts.MotionEventTest",
+ "include-filter": "android.view.cts.PointerCaptureTest",
"include-filter": "android.view.cts.VerifyInputEventTest"
}
]
@@ -45,6 +54,14 @@
]
},
{
+ "name": "FrameworksServicesTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.input"
+ }
+ ]
+ },
+ {
"name": "CtsSecurityTestCases",
"options": [
{
diff --git a/services/inputflinger/UnwantedInteractionBlocker.cpp b/services/inputflinger/UnwantedInteractionBlocker.cpp
index b69e16a..f57ff33 100644
--- a/services/inputflinger/UnwantedInteractionBlocker.cpp
+++ b/services/inputflinger/UnwantedInteractionBlocker.cpp
@@ -18,6 +18,7 @@
#include "UnwantedInteractionBlocker.h"
#include <android-base/stringprintf.h>
+#include <input/PrintTools.h>
#include <inttypes.h>
#include <linux/input-event-codes.h>
#include <linux/input.h>
@@ -80,47 +81,6 @@
return MT_TOOL_FINGER;
}
-static std::string addPrefix(std::string str, const std::string& prefix) {
- std::stringstream ss;
- bool newLineStarted = true;
- for (const auto& ch : str) {
- if (newLineStarted) {
- ss << prefix;
- newLineStarted = false;
- }
- if (ch == '\n') {
- newLineStarted = true;
- }
- ss << ch;
- }
- return ss.str();
-}
-
-template <typename T>
-static std::string dumpSet(const std::set<T>& v) {
- static_assert(std::is_integral<T>::value, "Only integral types can be printed.");
- std::string out;
- for (const T& entry : v) {
- out += out.empty() ? "{" : ", ";
- out += android::base::StringPrintf("%i", entry);
- }
- return out.empty() ? "{}" : (out + "}");
-}
-
-template <typename K, typename V>
-static std::string dumpMap(const std::map<K, V>& map) {
- static_assert(std::is_integral<K>::value, "Keys should have integral type to be printed.");
- static_assert(std::is_integral<V>::value, "Values should have integral type to be printed.");
- std::string out;
- for (const auto& [k, v] : map) {
- if (!out.empty()) {
- out += "\n";
- }
- out += android::base::StringPrintf("%i : %i", static_cast<int>(k), static_cast<int>(v));
- }
- return out;
-}
-
static std::string dumpDeviceInfo(const AndroidPalmFilterDeviceInfo& info) {
std::string out;
out += StringPrintf("max_x = %.2f\n", info.max_x);
@@ -168,10 +128,6 @@
return AMOTION_EVENT_ACTION_MOVE;
}
-static const char* toString(bool value) {
- return value ? "true" : "false";
-}
-
std::string toString(const ::ui::InProgressTouchEvdev& touch) {
return StringPrintf("x=%.1f, y=%.1f, tracking_id=%i, slot=%zu,"
" pressure=%.1f, major=%i, minor=%i, "
@@ -356,69 +312,87 @@
UnwantedInteractionBlocker::UnwantedInteractionBlocker(InputListenerInterface& listener,
bool enablePalmRejection)
- : mListener(listener), mEnablePalmRejection(enablePalmRejection) {}
+ : mQueuedListener(listener), mEnablePalmRejection(enablePalmRejection) {}
void UnwantedInteractionBlocker::notifyConfigurationChanged(
const NotifyConfigurationChangedArgs* args) {
- mListener.notifyConfigurationChanged(args);
+ mQueuedListener.notifyConfigurationChanged(args);
+ mQueuedListener.flush();
}
void UnwantedInteractionBlocker::notifyKey(const NotifyKeyArgs* args) {
- mListener.notifyKey(args);
+ mQueuedListener.notifyKey(args);
+ mQueuedListener.flush();
}
void UnwantedInteractionBlocker::notifyMotion(const NotifyMotionArgs* args) {
- const std::vector<NotifyMotionArgs> processedArgs =
- mPreferStylusOverTouchBlocker.processMotion(*args);
- for (const NotifyMotionArgs& loopArgs : processedArgs) {
- notifyMotionInner(&loopArgs);
- }
+ { // acquire lock
+ std::scoped_lock lock(mLock);
+ const std::vector<NotifyMotionArgs> processedArgs =
+ mPreferStylusOverTouchBlocker.processMotion(*args);
+ for (const NotifyMotionArgs& loopArgs : processedArgs) {
+ notifyMotionLocked(&loopArgs);
+ }
+ } // release lock
+
+ // Call out to the next stage without holding the lock
+ mQueuedListener.flush();
}
-void UnwantedInteractionBlocker::notifyMotionInner(const NotifyMotionArgs* args) {
+void UnwantedInteractionBlocker::notifyMotionLocked(const NotifyMotionArgs* args) {
auto it = mPalmRejectors.find(args->deviceId);
const bool sendToPalmRejector = it != mPalmRejectors.end() && isFromTouchscreen(args->source);
if (!sendToPalmRejector) {
- mListener.notifyMotion(args);
+ mQueuedListener.notifyMotion(args);
return;
}
- const std::vector<NotifyMotionArgs> newMotions = it->second.processMotion(*args);
- for (const NotifyMotionArgs& newArgs : newMotions) {
- mListener.notifyMotion(&newArgs);
+ std::vector<NotifyMotionArgs> processedArgs = it->second.processMotion(*args);
+ for (const NotifyMotionArgs& loopArgs : processedArgs) {
+ mQueuedListener.notifyMotion(&loopArgs);
}
}
void UnwantedInteractionBlocker::notifySwitch(const NotifySwitchArgs* args) {
- mListener.notifySwitch(args);
+ mQueuedListener.notifySwitch(args);
+ mQueuedListener.flush();
}
void UnwantedInteractionBlocker::notifySensor(const NotifySensorArgs* args) {
- mListener.notifySensor(args);
+ mQueuedListener.notifySensor(args);
+ mQueuedListener.flush();
}
void UnwantedInteractionBlocker::notifyVibratorState(const NotifyVibratorStateArgs* args) {
- mListener.notifyVibratorState(args);
+ mQueuedListener.notifyVibratorState(args);
+ mQueuedListener.flush();
}
void UnwantedInteractionBlocker::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
- auto it = mPalmRejectors.find(args->deviceId);
- if (it != mPalmRejectors.end()) {
- AndroidPalmFilterDeviceInfo info = it->second.getPalmFilterDeviceInfo();
- // Re-create the object instead of resetting it
- mPalmRejectors.erase(it);
- mPalmRejectors.emplace(args->deviceId, info);
- }
- mListener.notifyDeviceReset(args);
- mPreferStylusOverTouchBlocker.notifyDeviceReset(*args);
+ { // acquire lock
+ std::scoped_lock lock(mLock);
+ auto it = mPalmRejectors.find(args->deviceId);
+ if (it != mPalmRejectors.end()) {
+ AndroidPalmFilterDeviceInfo info = it->second.getPalmFilterDeviceInfo();
+ // Re-create the object instead of resetting it
+ mPalmRejectors.erase(it);
+ mPalmRejectors.emplace(args->deviceId, info);
+ }
+ mQueuedListener.notifyDeviceReset(args);
+ mPreferStylusOverTouchBlocker.notifyDeviceReset(*args);
+ } // release lock
+ // Send events to the next stage without holding the lock
+ mQueuedListener.flush();
}
void UnwantedInteractionBlocker::notifyPointerCaptureChanged(
const NotifyPointerCaptureChangedArgs* args) {
- mListener.notifyPointerCaptureChanged(args);
+ mQueuedListener.notifyPointerCaptureChanged(args);
+ mQueuedListener.flush();
}
void UnwantedInteractionBlocker::notifyInputDevicesChanged(
const std::vector<InputDeviceInfo>& inputDevices) {
+ std::scoped_lock lock(mLock);
if (!mEnablePalmRejection) {
// Palm rejection is disabled. Don't create any palm rejector objects.
return;
@@ -450,20 +424,23 @@
}
void UnwantedInteractionBlocker::dump(std::string& dump) {
+ std::scoped_lock lock(mLock);
dump += "UnwantedInteractionBlocker:\n";
dump += " mPreferStylusOverTouchBlocker:\n";
- dump += addPrefix(mPreferStylusOverTouchBlocker.dump(), " ");
+ dump += addLinePrefix(mPreferStylusOverTouchBlocker.dump(), " ");
dump += StringPrintf(" mEnablePalmRejection: %s\n", toString(mEnablePalmRejection));
dump += StringPrintf(" isPalmRejectionEnabled (flag value): %s\n",
toString(isPalmRejectionEnabled()));
dump += mPalmRejectors.empty() ? " mPalmRejectors: None\n" : " mPalmRejectors:\n";
for (const auto& [deviceId, palmRejector] : mPalmRejectors) {
dump += StringPrintf(" deviceId = %" PRId32 ":\n", deviceId);
- dump += addPrefix(palmRejector.dump(), " ");
+ dump += addLinePrefix(palmRejector.dump(), " ");
}
}
-void UnwantedInteractionBlocker::monitor() {}
+void UnwantedInteractionBlocker::monitor() {
+ std::scoped_lock lock(mLock);
+}
UnwantedInteractionBlocker::~UnwantedInteractionBlocker() {}
@@ -529,9 +506,9 @@
std::string SlotState::dump() const {
std::string out = "mSlotsByPointerId:\n";
- out += addPrefix(dumpMap(mSlotsByPointerId), " ") + "\n";
+ out += addLinePrefix(dumpMap(mSlotsByPointerId), " ") + "\n";
out += "mPointerIdsBySlot:\n";
- out += addPrefix(dumpMap(mPointerIdsBySlot), " ") + "\n";
+ out += addLinePrefix(dumpMap(mPointerIdsBySlot), " ") + "\n";
return out;
}
@@ -689,9 +666,9 @@
std::string PalmRejector::dump() const {
std::string out;
out += "mDeviceInfo:\n";
- out += addPrefix(dumpDeviceInfo(mDeviceInfo), " ");
+ out += addLinePrefix(dumpDeviceInfo(mDeviceInfo), " ");
out += "mSlotState:\n";
- out += addPrefix(mSlotState.dump(), " ");
+ out += addLinePrefix(mSlotState.dump(), " ");
out += "mSuppressedPointerIds: ";
out += dumpSet(mSuppressedPointerIds) + "\n";
return out;
diff --git a/services/inputflinger/UnwantedInteractionBlocker.h b/services/inputflinger/UnwantedInteractionBlocker.h
index 8a1cd72..a433764 100644
--- a/services/inputflinger/UnwantedInteractionBlocker.h
+++ b/services/inputflinger/UnwantedInteractionBlocker.h
@@ -19,6 +19,7 @@
#include <map>
#include <set>
+#include <android-base/thread_annotations.h>
#include "include/UnwantedInteractionBlockerInterface.h"
#include "ui/events/ozone/evdev/touch_filter/neural_stylus_palm_detection_filter_util.h"
#include "ui/events/ozone/evdev/touch_filter/palm_detection_filter.h"
@@ -86,18 +87,20 @@
~UnwantedInteractionBlocker();
private:
+ std::mutex mLock;
// The next stage to pass input events to
- InputListenerInterface& mListener;
+
+ QueuedInputListener mQueuedListener;
const bool mEnablePalmRejection;
// When stylus is down, ignore touch
- PreferStylusOverTouchBlocker mPreferStylusOverTouchBlocker;
+ PreferStylusOverTouchBlocker mPreferStylusOverTouchBlocker GUARDED_BY(mLock);
// Detect and reject unwanted palms on screen
// Use a separate palm rejector for every touch device.
- std::map<int32_t /*deviceId*/, PalmRejector> mPalmRejectors;
+ std::map<int32_t /*deviceId*/, PalmRejector> mPalmRejectors GUARDED_BY(mLock);
// TODO(b/210159205): delete this when simultaneous stylus and touch is supported
- void notifyMotionInner(const NotifyMotionArgs* args);
+ void notifyMotionLocked(const NotifyMotionArgs* args) REQUIRES(mLock);
};
class SlotState {
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index 32eec29..a2e60c4 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -31,11 +31,11 @@
namespace android::inputdispatcher {
// An arbitrary device id.
-static const int32_t DEVICE_ID = 1;
+constexpr int32_t DEVICE_ID = 1;
-// An arbitrary injector pid / uid pair that has permission to inject events.
-static const int32_t INJECTOR_PID = 999;
-static const int32_t INJECTOR_UID = 1001;
+// The default pid and uid for windows created by the test.
+constexpr int32_t WINDOW_PID = 999;
+constexpr int32_t WINDOW_UID = 1001;
static constexpr std::chrono::duration INJECT_EVENT_TIMEOUT = 5s;
static constexpr std::chrono::nanoseconds DISPATCHING_TIMEOUT = 100ms;
@@ -108,8 +108,6 @@
void pokeUserActivity(nsecs_t, int32_t, int32_t) override {}
- bool checkInjectEventsPermissionNonReentrant(int32_t, int32_t) override { return false; }
-
void onPointerDownOutsideFocus(const sp<IBinder>& newToken) override {}
void setPointerCapture(const PointerCaptureRequest&) override {}
@@ -196,8 +194,8 @@
mInfo.globalScaleFactor = 1.0;
mInfo.touchableRegion.clear();
mInfo.addTouchableRegion(mFrame);
- mInfo.ownerPid = INJECTOR_PID;
- mInfo.ownerUid = INJECTOR_UID;
+ mInfo.ownerPid = WINDOW_PID;
+ mInfo.ownerUid = WINDOW_UID;
mInfo.displayId = ADISPLAY_ID_DEFAULT;
}
@@ -310,14 +308,14 @@
for (auto _ : state) {
MotionEvent event = generateMotionEvent();
// Send ACTION_DOWN
- dispatcher.injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, INJECT_EVENT_TIMEOUT,
+ dispatcher.injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ INJECT_EVENT_TIMEOUT,
POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
// Send ACTION_UP
event.setAction(AMOTION_EVENT_ACTION_UP);
- dispatcher.injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, INJECT_EVENT_TIMEOUT,
+ dispatcher.injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ INJECT_EVENT_TIMEOUT,
POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
window->consumeEvent();
diff --git a/services/inputflinger/dispatcher/DebugConfig.h b/services/inputflinger/dispatcher/DebugConfig.h
new file mode 100644
index 0000000..4f8995f
--- /dev/null
+++ b/services/inputflinger/dispatcher/DebugConfig.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UI_INPUT_DISPATCHER_DEBUG_CONFIG_H
+#define _UI_INPUT_DISPATCHER_DEBUG_CONFIG_H
+
+#define LOG_TAG "InputDispatcher"
+
+#include <log/log.h>
+#include <log/log_event_list.h>
+
+namespace android::inputdispatcher {
+/**
+ * Log detailed debug messages about each inbound event notification to the dispatcher.
+ * Enable this via "adb shell setprop log.tag.InputDispatcherInboundEvent DEBUG" (requires restart)
+ */
+const bool DEBUG_INBOUND_EVENT_DETAILS =
+ __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "InboundEvent", ANDROID_LOG_INFO);
+
+/**
+ * Log detailed debug messages about each outbound event processed by the dispatcher.
+ * Enable this via "adb shell setprop log.tag.InputDispatcherOutboundEvent DEBUG" (requires restart)
+ */
+const bool DEBUG_OUTBOUND_EVENT_DETAILS =
+ __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "OutboundEvent", ANDROID_LOG_INFO);
+
+/**
+ * Log debug messages about the dispatch cycle.
+ * Enable this via "adb shell setprop log.tag.InputDispatcherDispatchCycle DEBUG" (requires restart)
+ */
+const bool DEBUG_DISPATCH_CYCLE =
+ __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "DispatchCycle", ANDROID_LOG_INFO);
+
+/**
+ * Log debug messages about channel creation
+ * Enable this via "adb shell setprop log.tag.InputDispatcherChannelCreation DEBUG" (requires
+ * restart)
+ */
+const bool DEBUG_CHANNEL_CREATION =
+ __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "ChannelCreation", ANDROID_LOG_INFO);
+
+/**
+ * Log debug messages about input event injection.
+ * Enable this via "adb shell setprop log.tag.InputDispatcherInjection DEBUG" (requires restart)
+ */
+const bool DEBUG_INJECTION =
+ __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Injection", ANDROID_LOG_INFO);
+
+/**
+ * Log debug messages about input focus tracking.
+ * Enable this via "adb shell setprop log.tag.InputDispatcherFocus DEBUG" (requires restart)
+ */
+const bool DEBUG_FOCUS =
+ __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Focus", ANDROID_LOG_INFO);
+
+/**
+ * Log debug messages about touch mode event
+ * Enable this via "adb shell setprop log.tag.InputDispatcherTouchMode DEBUG" (requires restart)
+ */
+const bool DEBUG_TOUCH_MODE =
+ __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "TouchMode", ANDROID_LOG_INFO);
+
+/**
+ * Log debug messages about touch occlusion
+ * Enable this via "adb shell setprop log.tag.InputDispatcherTouchOcclusion DEBUG" (requires
+ * restart)
+ */
+const bool DEBUG_TOUCH_OCCLUSION =
+ __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "TouchOcclusion", ANDROID_LOG_INFO);
+
+/**
+ * Log debug messages about the app switch latency optimization.
+ * Enable this via "adb shell setprop log.tag.InputDispatcherAppSwitch DEBUG" (requires restart)
+ */
+const bool DEBUG_APP_SWITCH =
+ __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "AppSwitch", ANDROID_LOG_INFO);
+
+/**
+ * Log debug messages about hover events.
+ * Enable this via "adb shell setprop log.tag.InputDispatcherHover DEBUG" (requires restart)
+ */
+const bool DEBUG_HOVER =
+ __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Hover", ANDROID_LOG_INFO);
+} // namespace android::inputdispatcher
+
+#endif // _UI_INPUT_DISPATCHER_DEBUG_CONFIG_H
\ No newline at end of file
diff --git a/services/inputflinger/dispatcher/InjectionState.cpp b/services/inputflinger/dispatcher/InjectionState.cpp
index c8024a6..c2d3ad6 100644
--- a/services/inputflinger/dispatcher/InjectionState.cpp
+++ b/services/inputflinger/dispatcher/InjectionState.cpp
@@ -20,10 +20,9 @@
namespace android::inputdispatcher {
-InjectionState::InjectionState(int32_t injectorPid, int32_t injectorUid)
+InjectionState::InjectionState(const std::optional<int32_t>& targetUid)
: refCount(1),
- injectorPid(injectorPid),
- injectorUid(injectorUid),
+ targetUid(targetUid),
injectionResult(android::os::InputEventInjectionResult::PENDING),
injectionIsAsync(false),
pendingForegroundDispatches(0) {}
diff --git a/services/inputflinger/dispatcher/InjectionState.h b/services/inputflinger/dispatcher/InjectionState.h
index 0bfafb1..90cf150 100644
--- a/services/inputflinger/dispatcher/InjectionState.h
+++ b/services/inputflinger/dispatcher/InjectionState.h
@@ -27,13 +27,12 @@
struct InjectionState {
mutable int32_t refCount;
- int32_t injectorPid;
- int32_t injectorUid;
+ std::optional<int32_t> targetUid;
android::os::InputEventInjectionResult injectionResult; // initially PENDING
bool injectionIsAsync; // set to true if injection is not waiting for the result
int32_t pendingForegroundDispatches; // the number of foreground dispatches in progress
- InjectionState(int32_t injectorPid, int32_t injectorUid);
+ explicit InjectionState(const std::optional<int32_t>& targetUid);
void release();
private:
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 7852b30..4d25c59 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -27,8 +27,6 @@
#include <ftl/enum.h>
#include <gui/SurfaceComposerClient.h>
#include <input/InputDevice.h>
-#include <log/log.h>
-#include <log/log_event_list.h>
#include <powermanager/PowerManager.h>
#include <unistd.h>
#include <utils/Trace.h>
@@ -42,6 +40,7 @@
#include <sstream>
#include "Connection.h"
+#include "DebugConfig.h"
#include "InputDispatcher.h"
#define INDENT " "
@@ -65,79 +64,6 @@
namespace android::inputdispatcher {
namespace {
-
-/**
- * Log detailed debug messages about each inbound event notification to the dispatcher.
- * Enable this via "adb shell setprop log.tag.InputDispatcherInboundEvent DEBUG" (requires restart)
- */
-const bool DEBUG_INBOUND_EVENT_DETAILS =
- __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "InboundEvent", ANDROID_LOG_INFO);
-
-/**
- * Log detailed debug messages about each outbound event processed by the dispatcher.
- * Enable this via "adb shell setprop log.tag.InputDispatcherOutboundEvent DEBUG" (requires restart)
- */
-const bool DEBUG_OUTBOUND_EVENT_DETAILS =
- __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "OutboundEvent", ANDROID_LOG_INFO);
-
-/**
- * Log debug messages about the dispatch cycle.
- * Enable this via "adb shell setprop log.tag.InputDispatcherDispatchCycle DEBUG" (requires restart)
- */
-const bool DEBUG_DISPATCH_CYCLE =
- __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "DispatchCycle", ANDROID_LOG_INFO);
-
-/**
- * Log debug messages about channel creation
- * Enable this via "adb shell setprop log.tag.InputDispatcherChannelCreation DEBUG" (requires
- * restart)
- */
-const bool DEBUG_CHANNEL_CREATION =
- __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "ChannelCreation", ANDROID_LOG_INFO);
-
-/**
- * Log debug messages about input event injection.
- * Enable this via "adb shell setprop log.tag.InputDispatcherInjection DEBUG" (requires restart)
- */
-const bool DEBUG_INJECTION =
- __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Injection", ANDROID_LOG_INFO);
-
-/**
- * Log debug messages about input focus tracking.
- * Enable this via "adb shell setprop log.tag.InputDispatcherFocus DEBUG" (requires restart)
- */
-const bool DEBUG_FOCUS =
- __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Focus", ANDROID_LOG_INFO);
-
-/**
- * Log debug messages about touch mode event
- * Enable this via "adb shell setprop log.tag.InputDispatcherTouchMode DEBUG" (requires restart)
- */
-const bool DEBUG_TOUCH_MODE =
- __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "TouchMode", ANDROID_LOG_INFO);
-
-/**
- * Log debug messages about touch occlusion
- * Enable this via "adb shell setprop log.tag.InputDispatcherTouchOcclusion DEBUG" (requires
- * restart)
- */
-const bool DEBUG_TOUCH_OCCLUSION =
- __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "TouchOcclusion", ANDROID_LOG_INFO);
-
-/**
- * Log debug messages about the app switch latency optimization.
- * Enable this via "adb shell setprop log.tag.InputDispatcherAppSwitch DEBUG" (requires restart)
- */
-const bool DEBUG_APP_SWITCH =
- __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "AppSwitch", ANDROID_LOG_INFO);
-
-/**
- * Log debug messages about hover events.
- * Enable this via "adb shell setprop log.tag.InputDispatcherHover DEBUG" (requires restart)
- */
-const bool DEBUG_HOVER =
- __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Hover", ANDROID_LOG_INFO);
-
// Temporarily releases a held mutex for the lifetime of the instance.
// Named to match std::scoped_lock
class scoped_unlock {
@@ -578,6 +504,27 @@
return false;
}
+// Checks targeted injection using the window's owner's uid.
+// Returns an empty string if an entry can be sent to the given window, or an error message if the
+// entry is a targeted injection whose uid target doesn't match the window owner.
+std::optional<std::string> verifyTargetedInjection(const sp<WindowInfoHandle>& window,
+ const EventEntry& entry) {
+ if (entry.injectionState == nullptr || !entry.injectionState->targetUid) {
+ // The event was not injected, or the injected event does not target a window.
+ return {};
+ }
+ const int32_t uid = *entry.injectionState->targetUid;
+ if (window == nullptr) {
+ return StringPrintf("No valid window target for injection into uid %d.", uid);
+ }
+ if (entry.injectionState->targetUid != window->getInfo()->ownerUid) {
+ return StringPrintf("Injected event targeted at uid %d would be dispatched to window '%s' "
+ "owned by uid %d.",
+ uid, window->getName().c_str(), window->getInfo()->ownerUid);
+ }
+ return {};
+}
+
} // namespace
// --- InputDispatcher ---
@@ -1036,6 +983,8 @@
switch (entry.type) {
case EventEntry::Type::KEY: {
+ LOG_ALWAYS_FATAL_IF((entry.policyFlags & POLICY_FLAG_TRUSTED) == 0,
+ "Unexpected untrusted event.");
// Optimize app switch latency.
// If the application takes too long to catch up then we drop all events preceding
// the app switch key.
@@ -1073,6 +1022,8 @@
}
case EventEntry::Type::MOTION: {
+ LOG_ALWAYS_FATAL_IF((entry.policyFlags & POLICY_FLAG_TRUSTED) == 0,
+ "Unexpected untrusted event.");
if (shouldPruneInboundQueueLocked(static_cast<MotionEntry&>(entry))) {
mNextUnblockedEvent = mInboundQueue.back();
needWake = true;
@@ -1720,8 +1671,7 @@
}
setInjectionResult(*entry, injectionResult);
- if (injectionResult == InputEventInjectionResult::PERMISSION_DENIED) {
- ALOGW("Permission denied, dropping the motion (isPointer=%s)", toString(isPointerEvent));
+ if (injectionResult == InputEventInjectionResult::TARGET_MISMATCH) {
return true;
}
if (injectionResult != InputEventInjectionResult::SUCCEEDED) {
@@ -1972,9 +1922,10 @@
// we have a valid, non-null focused window
resetNoFocusedWindowTimeoutLocked();
- // Check permissions.
- if (!checkInjectionPermission(focusedWindowHandle, entry.injectionState)) {
- return InputEventInjectionResult::PERMISSION_DENIED;
+ // Verify targeted injection.
+ if (const auto err = verifyTargetedInjection(focusedWindowHandle, entry); err) {
+ ALOGW("Dropping injected event: %s", (*err).c_str());
+ return InputEventInjectionResult::TARGET_MISMATCH;
}
if (focusedWindowHandle->getInfo()->inputConfig.test(
@@ -2040,11 +1991,6 @@
nsecs_t currentTime, const MotionEntry& entry, std::vector<InputTarget>& inputTargets,
nsecs_t* nextWakeupTime, bool* outConflictingPointerActions) {
ATRACE_CALL();
- enum InjectionPermission {
- INJECTION_PERMISSION_UNKNOWN,
- INJECTION_PERMISSION_GRANTED,
- INJECTION_PERMISSION_DENIED
- };
// For security reasons, we defer updating the touch state until we are sure that
// event injection will be allowed.
@@ -2054,7 +2000,6 @@
// Update the touch state as needed based on the properties of the touch event.
InputEventInjectionResult injectionResult = InputEventInjectionResult::PENDING;
- InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN;
sp<WindowInfoHandle> newHoverWindowHandle(mLastHoverWindowHandle);
sp<WindowInfoHandle> newTouchedWindowHandle;
@@ -2103,7 +2048,7 @@
"in display %" PRId32,
displayId);
// TODO: test multiple simultaneous input streams.
- injectionResult = InputEventInjectionResult::PERMISSION_DENIED;
+ injectionResult = InputEventInjectionResult::FAILED;
switchedDevice = false;
wrongDevice = true;
goto Failed;
@@ -2136,6 +2081,14 @@
newTouchedWindowHandle = tempTouchState.getFirstForegroundWindowHandle();
}
+ // Verify targeted injection.
+ if (const auto err = verifyTargetedInjection(newTouchedWindowHandle, entry); err) {
+ ALOGW("Dropping injected touch event: %s", (*err).c_str());
+ injectionResult = os::InputEventInjectionResult::TARGET_MISMATCH;
+ newTouchedWindowHandle = nullptr;
+ goto Failed;
+ }
+
// Figure out whether splitting will be allowed for this window.
if (newTouchedWindowHandle != nullptr) {
if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {
@@ -2179,6 +2132,11 @@
for (const sp<WindowInfoHandle>& windowHandle : newTouchedWindows) {
const WindowInfo& info = *windowHandle->getInfo();
+ // Skip spy window targets that are not valid for targeted injection.
+ if (const auto err = verifyTargetedInjection(windowHandle, entry); err) {
+ continue;
+ }
+
if (info.inputConfig.test(WindowInfo::InputConfig::PAUSE_DISPATCHING)) {
ALOGI("Not sending touch event to %s because it is paused",
windowHandle->getName().c_str());
@@ -2272,6 +2230,14 @@
newTouchedWindowHandle =
findTouchedWindowAtLocked(displayId, x, y, &tempTouchState, isStylus);
+ // Verify targeted injection.
+ if (const auto err = verifyTargetedInjection(newTouchedWindowHandle, entry); err) {
+ ALOGW("Dropping injected event: %s", (*err).c_str());
+ injectionResult = os::InputEventInjectionResult::TARGET_MISMATCH;
+ newTouchedWindowHandle = nullptr;
+ goto Failed;
+ }
+
// Drop touch events if requested by input feature
if (newTouchedWindowHandle != nullptr &&
shouldDropInput(entry, newTouchedWindowHandle)) {
@@ -2363,19 +2329,26 @@
goto Failed;
}
- // Check permission to inject into all touched foreground windows.
- if (std::any_of(tempTouchState.windows.begin(), tempTouchState.windows.end(),
- [this, &entry](const TouchedWindow& touchedWindow) {
- return (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) != 0 &&
- !checkInjectionPermission(touchedWindow.windowHandle,
- entry.injectionState);
- })) {
- injectionResult = InputEventInjectionResult::PERMISSION_DENIED;
- injectionPermission = INJECTION_PERMISSION_DENIED;
- goto Failed;
+ // Ensure that all touched windows are valid for injection.
+ if (entry.injectionState != nullptr) {
+ std::string errs;
+ for (const TouchedWindow& touchedWindow : tempTouchState.windows) {
+ if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
+ // Allow ACTION_OUTSIDE events generated by targeted injection to be
+ // dispatched to any uid, since the coords will be zeroed out later.
+ continue;
+ }
+ const auto err = verifyTargetedInjection(touchedWindow.windowHandle, entry);
+ if (err) errs += "\n - " + *err;
+ }
+ if (!errs.empty()) {
+ ALOGW("Dropping targeted injection: At least one touched window is not owned by uid "
+ "%d:%s",
+ *entry.injectionState->targetUid, errs.c_str());
+ injectionResult = InputEventInjectionResult::TARGET_MISMATCH;
+ goto Failed;
+ }
}
- // Permission granted to inject into all touched foreground windows.
- injectionPermission = INJECTION_PERMISSION_GRANTED;
// Check whether windows listening for outside touches are owned by the same UID. If it is
// set the policy flag that we will not reveal coordinate information to this window.
@@ -2441,19 +2414,6 @@
tempTouchState.filterNonAsIsTouchWindows();
Failed:
- // Check injection permission once and for all.
- if (injectionPermission == INJECTION_PERMISSION_UNKNOWN) {
- if (checkInjectionPermission(nullptr, entry.injectionState)) {
- injectionPermission = INJECTION_PERMISSION_GRANTED;
- } else {
- injectionPermission = INJECTION_PERMISSION_DENIED;
- }
- }
-
- if (injectionPermission != INJECTION_PERMISSION_GRANTED) {
- return injectionResult;
- }
-
// Update final pieces of touch state if the injector had permission.
if (!wrongDevice) {
if (switchedDevice) {
@@ -2685,26 +2645,6 @@
}
}
-bool InputDispatcher::checkInjectionPermission(const sp<WindowInfoHandle>& windowHandle,
- const InjectionState* injectionState) {
- if (injectionState &&
- (windowHandle == nullptr ||
- windowHandle->getInfo()->ownerUid != injectionState->injectorUid) &&
- !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) {
- if (windowHandle != nullptr) {
- ALOGW("Permission denied: injecting event from pid %d uid %d to window %s "
- "owned by uid %d",
- injectionState->injectorPid, injectionState->injectorUid,
- windowHandle->getName().c_str(), windowHandle->getInfo()->ownerUid);
- } else {
- ALOGW("Permission denied: injecting event from pid %d uid %d",
- injectionState->injectorPid, injectionState->injectorUid);
- }
- return false;
- }
- return true;
-}
-
/**
* Indicate whether one window handle should be considered as obscuring
* another window handle. We only check a few preconditions. Actually
@@ -4223,20 +4163,20 @@
}
}
-InputEventInjectionResult InputDispatcher::injectInputEvent(
- const InputEvent* event, int32_t injectorPid, int32_t injectorUid,
- InputEventInjectionSync syncMode, std::chrono::milliseconds timeout, uint32_t policyFlags) {
+InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* event,
+ std::optional<int32_t> targetUid,
+ InputEventInjectionSync syncMode,
+ std::chrono::milliseconds timeout,
+ uint32_t policyFlags) {
if (DEBUG_INBOUND_EVENT_DETAILS) {
- ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, "
- "syncMode=%d, timeout=%lld, policyFlags=0x%08x",
- event->getType(), injectorPid, injectorUid, syncMode, timeout.count(), policyFlags);
+ ALOGD("injectInputEvent - eventType=%d, targetUid=%s, syncMode=%d, timeout=%lld, "
+ "policyFlags=0x%08x",
+ event->getType(), targetUid ? std::to_string(*targetUid).c_str() : "none", syncMode,
+ timeout.count(), policyFlags);
}
nsecs_t endTime = now() + std::chrono::duration_cast<std::chrono::nanoseconds>(timeout).count();
- policyFlags |= POLICY_FLAG_INJECTED;
- if (hasInjectionPermission(injectorPid, injectorUid)) {
- policyFlags |= POLICY_FLAG_TRUSTED;
- }
+ policyFlags |= POLICY_FLAG_INJECTED | POLICY_FLAG_TRUSTED;
// For all injected events, set device id = VIRTUAL_KEYBOARD_ID. The only exception is events
// that have gone through the InputFilter. If the event passed through the InputFilter, assign
@@ -4377,7 +4317,7 @@
return InputEventInjectionResult::FAILED;
}
- InjectionState* injectionState = new InjectionState(injectorPid, injectorUid);
+ InjectionState* injectionState = new InjectionState(targetUid);
if (syncMode == InputEventInjectionSync::NONE) {
injectionState->injectionIsAsync = true;
}
@@ -4449,8 +4389,7 @@
} // release lock
if (DEBUG_INJECTION) {
- ALOGD("injectInputEvent - Finished with result %d. injectorPid=%d, injectorUid=%d",
- injectionResult, injectorPid, injectorUid);
+ ALOGD("injectInputEvent - Finished with result %d.", injectionResult);
}
return injectionResult;
@@ -4489,19 +4428,12 @@
return result;
}
-bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) {
- return injectorUid == 0 ||
- mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid);
-}
-
void InputDispatcher::setInjectionResult(EventEntry& entry,
InputEventInjectionResult injectionResult) {
InjectionState* injectionState = entry.injectionState;
if (injectionState) {
if (DEBUG_INJECTION) {
- ALOGD("Setting input event injection result to %d. "
- "injectorPid=%d, injectorUid=%d",
- injectionResult, injectionState->injectorPid, injectionState->injectorUid);
+ ALOGD("Setting input event injection result to %d.", injectionResult);
}
if (injectionState->injectionIsAsync && !(entry.policyFlags & POLICY_FLAG_FILTERED)) {
@@ -4510,12 +4442,12 @@
case InputEventInjectionResult::SUCCEEDED:
ALOGV("Asynchronous input event injection succeeded.");
break;
+ case InputEventInjectionResult::TARGET_MISMATCH:
+ ALOGV("Asynchronous input event injection target mismatch.");
+ break;
case InputEventInjectionResult::FAILED:
ALOGW("Asynchronous input event injection failed.");
break;
- case InputEventInjectionResult::PERMISSION_DENIED:
- ALOGW("Asynchronous input event injection permission denied.");
- break;
case InputEventInjectionResult::TIMED_OUT:
ALOGW("Asynchronous input event injection timed out.");
break;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 34aed3b..ed89ed0 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -104,7 +104,7 @@
void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
android::os::InputEventInjectionResult injectInputEvent(
- const InputEvent* event, int32_t injectorPid, int32_t injectorUid,
+ const InputEvent* event, std::optional<int32_t> targetUid,
android::os::InputEventInjectionSync syncMode, std::chrono::milliseconds timeout,
uint32_t policyFlags) override;
@@ -279,7 +279,6 @@
// Event injection and synchronization.
std::condition_variable mInjectionResultAvailable;
- bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid);
void setInjectionResult(EventEntry& entry,
android::os::InputEventInjectionResult injectionResult);
void transformMotionEntryForInjectionLocked(MotionEntry&,
@@ -555,8 +554,6 @@
void addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets, int32_t displayId)
REQUIRES(mLock);
void pokeUserActivityLocked(const EventEntry& eventEntry) REQUIRES(mLock);
- bool checkInjectionPermission(const sp<android::gui::WindowInfoHandle>& windowHandle,
- const InjectionState* injectionState);
// Enqueue a drag event if needed, and update the touch state.
// Uses findTouchedWindowTargetsLocked to make the decision
void addDragEventLocked(const MotionEntry& entry) REQUIRES(mLock);
diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp
index ad3c615..f46a8bc 100644
--- a/services/inputflinger/dispatcher/InputState.cpp
+++ b/services/inputflinger/dispatcher/InputState.cpp
@@ -14,10 +14,12 @@
* limitations under the License.
*/
+#include "DebugConfig.h"
#include "input/InputDevice.h"
#include "InputState.h"
+#include <cinttypes>
#include "InputDispatcher.h"
namespace android::inputdispatcher {
@@ -100,11 +102,11 @@
mMotionMementos.erase(mMotionMementos.begin() + index);
return true;
}
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("Dropping inconsistent motion up or cancel event: deviceId=%d, source=%08x, "
- "displayId=%" PRId32 ", actionMasked=%d",
- entry.deviceId, entry.source, entry.displayId, actionMasked);
-#endif
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ ALOGD("Dropping inconsistent motion up or cancel event: deviceId=%d, source=%08x, "
+ "displayId=%" PRId32 ", actionMasked=%d",
+ entry.deviceId, entry.source, entry.displayId, actionMasked);
+ }
return false;
}
@@ -157,11 +159,11 @@
return true;
}
}
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("Dropping inconsistent motion pointer up/down or move event: "
- "deviceId=%d, source=%08x, displayId=%" PRId32 ", actionMasked=%d",
- entry.deviceId, entry.source, entry.displayId, actionMasked);
-#endif
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ ALOGD("Dropping inconsistent motion pointer up/down or move event: "
+ "deviceId=%d, source=%08x, displayId=%" PRId32 ", actionMasked=%d",
+ entry.deviceId, entry.source, entry.displayId, actionMasked);
+ }
return false;
}
@@ -171,11 +173,11 @@
mMotionMementos.erase(mMotionMementos.begin() + index);
return true;
}
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("Dropping inconsistent motion hover exit event: deviceId=%d, source=%08x, "
- "displayId=%" PRId32,
- entry.deviceId, entry.source, entry.displayId);
-#endif
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ ALOGD("Dropping inconsistent motion hover exit event: deviceId=%d, source=%08x, "
+ "displayId=%" PRId32,
+ entry.deviceId, entry.source, entry.displayId);
+ }
return false;
}
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index d7bc5fb..67fed8b 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -68,10 +68,16 @@
* input injection to proceed.
* Returns one of the INPUT_EVENT_INJECTION_XXX constants.
*
- * This method may be called on any thread (usually by the input manager).
+ * If a targetUid is provided, InputDispatcher will only consider injecting the input event into
+ * windows owned by the provided uid. If the input event is targeted at a window that is not
+ * owned by the provided uid, input injection will fail. If no targetUid is provided, the input
+ * event will be dispatched as-is.
+ *
+ * This method may be called on any thread (usually by the input manager). The caller must
+ * perform all necessary permission checks prior to injecting events.
*/
virtual android::os::InputEventInjectionResult injectInputEvent(
- const InputEvent* event, int32_t injectorPid, int32_t injectorUid,
+ const InputEvent* event, std::optional<int32_t> targetUid,
android::os::InputEventInjectionSync syncMode, std::chrono::milliseconds timeout,
uint32_t policyFlags) = 0;
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
index de0b6da..575b3d7 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
@@ -125,15 +125,6 @@
/* Poke user activity for an event dispatched to a window. */
virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType, int32_t displayId) = 0;
- /* Checks whether a given application pid/uid has permission to inject input events
- * into other applications.
- *
- * This method is special in that its implementation promises to be non-reentrant and
- * is safe to call while holding other locks. (Most other methods make no such guarantees!)
- */
- virtual bool checkInjectEventsPermissionNonReentrant(int32_t injectorPid,
- int32_t injectorUid) = 0;
-
/* Notifies the policy that a pointer down event has occurred outside the current focused
* window.
*
diff --git a/services/inputflinger/include/UnwantedInteractionBlockerInterface.h b/services/inputflinger/include/UnwantedInteractionBlockerInterface.h
index 2327266..1a6f847 100644
--- a/services/inputflinger/include/UnwantedInteractionBlockerInterface.h
+++ b/services/inputflinger/include/UnwantedInteractionBlockerInterface.h
@@ -39,11 +39,11 @@
/**
* Dump the state of the interaction blocker.
- * This method may be called on any thread (usually by the input manager).
+ * This method may be called on any thread (usually by the input manager on a binder thread).
*/
virtual void dump(std::string& dump) = 0;
- /* Called by the heatbeat to ensures that the dispatcher has not deadlocked. */
+ /* Called by the heatbeat to ensures that the blocker has not deadlocked. */
virtual void monitor() = 0;
UnwantedInteractionBlockerInterface() {}
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 61e5fe3..91a666c 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -45,10 +45,10 @@
using namespace ftl::flag_operators;
// An arbitrary time value.
-static const nsecs_t ARBITRARY_TIME = 1234;
+static constexpr nsecs_t ARBITRARY_TIME = 1234;
// An arbitrary device id.
-static const int32_t DEVICE_ID = 1;
+static constexpr int32_t DEVICE_ID = 1;
// An arbitrary display id.
static constexpr int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT;
@@ -61,9 +61,12 @@
static constexpr int32_t POINTER_1_UP =
AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
-// An arbitrary injector pid / uid pair that has permission to inject events.
-static const int32_t INJECTOR_PID = 999;
-static const int32_t INJECTOR_UID = 1001;
+// The default pid and uid for windows created by the test.
+static constexpr int32_t WINDOW_PID = 999;
+static constexpr int32_t WINDOW_UID = 1001;
+
+// The default policy flags to use for event injection by tests.
+static constexpr uint32_t DEFAULT_POLICY_FLAGS = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
// An arbitrary pid of the gesture monitor window
static constexpr int32_t MONITOR_PID = 2001;
@@ -472,10 +475,6 @@
void pokeUserActivity(nsecs_t, int32_t, int32_t) override {}
- bool checkInjectEventsPermissionNonReentrant(int32_t pid, int32_t uid) override {
- return pid == INJECTOR_PID && uid == INJECTOR_UID;
- }
-
void onPointerDownOutsideFocus(const sp<IBinder>& newToken) override {
std::scoped_lock lock(mLock);
mOnPointerDownToken = newToken;
@@ -560,8 +559,8 @@
/*action*/ -1, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME,
ARBITRARY_TIME);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject key events with undefined action.";
// Rejects ACTION_MULTIPLE since it is not supported despite being defined in the API.
@@ -569,8 +568,8 @@
INVALID_HMAC, AKEY_EVENT_ACTION_MULTIPLE, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0,
ARBITRARY_TIME, ARBITRARY_TIME);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject key events with ACTION_MULTIPLE.";
}
@@ -599,8 +598,8 @@
ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject motion events with undefined action.";
// Rejects pointer down with invalid index.
@@ -611,8 +610,8 @@
ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject motion events with pointer down index too large.";
event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
@@ -623,8 +622,8 @@
identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject motion events with pointer down index too small.";
// Rejects pointer up with invalid index.
@@ -635,8 +634,8 @@
ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject motion events with pointer up index too large.";
event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
@@ -647,8 +646,8 @@
identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject motion events with pointer up index too small.";
// Rejects motion events with invalid number of pointers.
@@ -659,8 +658,8 @@
ARBITRARY_TIME,
/*pointerCount*/ 0, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject motion events with 0 pointers.";
event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
@@ -670,8 +669,8 @@
ARBITRARY_TIME,
/*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject motion events with more than MAX_POINTERS pointers.";
// Rejects motion events with invalid pointer ids.
@@ -683,8 +682,8 @@
ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject motion events with pointer ids less than 0.";
pointerProperties[0].id = MAX_POINTER_ID + 1;
@@ -695,8 +694,8 @@
ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject motion events with pointer ids greater than MAX_POINTER_ID.";
// Rejects motion events with duplicate pointer ids.
@@ -709,8 +708,8 @@
ARBITRARY_TIME,
/*pointerCount*/ 2, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject motion events with duplicate pointer ids.";
}
@@ -1013,8 +1012,8 @@
mInfo.globalScaleFactor = 1.0;
mInfo.touchableRegion.clear();
mInfo.addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT));
- mInfo.ownerPid = INJECTOR_PID;
- mInfo.ownerUid = INJECTOR_UID;
+ mInfo.ownerPid = WINDOW_PID;
+ mInfo.ownerUid = WINDOW_UID;
mInfo.displayId = displayId;
mInfo.inputConfig = WindowInfo::InputConfig::DEFAULT;
}
@@ -1296,7 +1295,8 @@
int32_t displayId = ADISPLAY_ID_NONE,
InputEventInjectionSync syncMode = InputEventInjectionSync::WAIT_FOR_RESULT,
std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
- bool allowKeyRepeat = true) {
+ bool allowKeyRepeat = true, std::optional<int32_t> targetUid = {},
+ uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
KeyEvent event;
nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
@@ -1305,13 +1305,11 @@
INVALID_HMAC, action, /* flags */ 0, AKEYCODE_A, KEY_A, AMETA_NONE,
repeatCount, currentTime, currentTime);
- int32_t policyFlags = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
if (!allowKeyRepeat) {
policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
}
// Inject event until dispatch out.
- return dispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, syncMode,
- injectionTimeout, policyFlags);
+ return dispatcher->injectInputEvent(&event, targetUid, syncMode, injectionTimeout, policyFlags);
}
static InputEventInjectionResult injectKeyDown(const std::unique_ptr<InputDispatcher>& dispatcher,
@@ -1454,10 +1452,10 @@
static InputEventInjectionResult injectMotionEvent(
const std::unique_ptr<InputDispatcher>& dispatcher, const MotionEvent& event,
std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
- InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT) {
- return dispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, injectionMode,
- injectionTimeout,
- POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
+ InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT,
+ std::optional<int32_t> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
+ return dispatcher->injectInputEvent(&event, targetUid, injectionMode, injectionTimeout,
+ policyFlags);
}
static InputEventInjectionResult injectMotionEvent(
@@ -1467,7 +1465,8 @@
AMOTION_EVENT_INVALID_CURSOR_POSITION},
std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT,
- nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC)) {
+ nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC),
+ std::optional<int32_t> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
MotionEvent event = MotionEventBuilder(action, source)
.displayId(displayId)
.eventTime(eventTime)
@@ -1479,7 +1478,8 @@
.build();
// Inject event until dispatch out.
- return injectMotionEvent(dispatcher, event, injectionTimeout, injectionMode);
+ return injectMotionEvent(dispatcher, event, injectionTimeout, injectionMode, targetUid,
+ policyFlags);
}
static InputEventInjectionResult injectMotionDown(
@@ -3574,8 +3574,8 @@
* FLAG_WINDOW_IS_PARTIALLY_OBSCURED.
*/
TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) {
- constexpr int32_t SLIPPERY_PID = INJECTOR_PID + 1;
- constexpr int32_t SLIPPERY_UID = INJECTOR_UID + 1;
+ constexpr int32_t SLIPPERY_PID = WINDOW_PID + 1;
+ constexpr int32_t SLIPPERY_UID = WINDOW_UID + 1;
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -4102,7 +4102,7 @@
const int32_t additionalPolicyFlags =
POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_DISABLE_KEY_REPEAT;
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/,
InputEventInjectionSync::WAIT_FOR_RESULT, 10ms,
policyFlags | additionalPolicyFlags));
@@ -4137,7 +4137,7 @@
const int32_t additionalPolicyFlags = POLICY_FLAG_PASS_TO_USER;
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/,
InputEventInjectionSync::WAIT_FOR_RESULT, 10ms,
policyFlags | additionalPolicyFlags));
@@ -4644,7 +4644,7 @@
const int32_t policyFlags = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
InputEventInjectionResult result =
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ mDispatcher->injectInputEvent(&event, {} /* targetUid */,
InputEventInjectionSync::WAIT_FOR_RESULT,
INJECT_EVENT_TIMEOUT, policyFlags);
ASSERT_EQ(InputEventInjectionResult::FAILED, result)
@@ -6558,8 +6558,8 @@
mWindow->consumeFocusEvent(true);
// Set initial touch mode to InputDispatcher::kDefaultInTouchMode.
- if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, INJECTOR_PID,
- INJECTOR_UID, /* hasPermission */ true)) {
+ if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, WINDOW_PID,
+ WINDOW_UID, /* hasPermission */ true)) {
mWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
mSecondWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
}
@@ -7190,4 +7190,149 @@
window->assertNoEvents();
}
+struct User {
+ int32_t mPid;
+ int32_t mUid;
+ uint32_t mPolicyFlags{DEFAULT_POLICY_FLAGS};
+ std::unique_ptr<InputDispatcher>& mDispatcher;
+
+ User(std::unique_ptr<InputDispatcher>& dispatcher, int32_t pid, int32_t uid)
+ : mPid(pid), mUid(uid), mDispatcher(dispatcher) {}
+
+ InputEventInjectionResult injectTargetedMotion(int32_t action) const {
+ return injectMotionEvent(mDispatcher, action, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {100, 200},
+ {AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION},
+ INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT,
+ systemTime(SYSTEM_TIME_MONOTONIC), {mUid}, mPolicyFlags);
+ }
+
+ InputEventInjectionResult injectTargetedKey(int32_t action) const {
+ return inputdispatcher::injectKey(mDispatcher, action, 0 /* repeatCount*/, ADISPLAY_ID_NONE,
+ InputEventInjectionSync::WAIT_FOR_RESULT,
+ INJECT_EVENT_TIMEOUT, false /*allowKeyRepeat*/, {mUid},
+ mPolicyFlags);
+ }
+
+ sp<FakeWindowHandle> createWindow() const {
+ std::shared_ptr<FakeApplicationHandle> overlayApplication =
+ std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window = new FakeWindowHandle(overlayApplication, mDispatcher,
+ "Owned Window", ADISPLAY_ID_DEFAULT);
+ window->setOwnerInfo(mPid, mUid);
+ return window;
+ }
+};
+
+using InputDispatcherTargetedInjectionTest = InputDispatcherTest;
+
+TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedWindow) {
+ auto owner = User(mDispatcher, 10, 11);
+ auto window = owner.createWindow();
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+
+ EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
+ owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
+ window->consumeMotionDown();
+
+ setFocusedWindow(window);
+ window->consumeFocusEvent(true);
+
+ EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
+ owner.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
+ window->consumeKeyDown(ADISPLAY_ID_NONE);
+}
+
+TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedWindow) {
+ auto owner = User(mDispatcher, 10, 11);
+ auto window = owner.createWindow();
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+
+ auto rando = User(mDispatcher, 20, 21);
+ EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
+ rando.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
+
+ setFocusedWindow(window);
+ window->consumeFocusEvent(true);
+
+ EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
+ rando.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
+ window->assertNoEvents();
+}
+
+TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedSpyWindow) {
+ auto owner = User(mDispatcher, 10, 11);
+ auto window = owner.createWindow();
+ auto spy = owner.createWindow();
+ spy->setSpy(true);
+ spy->setTrustedOverlay(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
+
+ EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
+ owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
+ spy->consumeMotionDown();
+ window->consumeMotionDown();
+}
+
+TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedSpyWindow) {
+ auto owner = User(mDispatcher, 10, 11);
+ auto window = owner.createWindow();
+
+ auto rando = User(mDispatcher, 20, 21);
+ auto randosSpy = rando.createWindow();
+ randosSpy->setSpy(true);
+ randosSpy->setTrustedOverlay(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {randosSpy, window}}});
+
+ // The event is targeted at owner's window, so injection should succeed, but the spy should
+ // not receive the event.
+ EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
+ owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
+ randosSpy->assertNoEvents();
+ window->consumeMotionDown();
+}
+
+TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoAnyWindowWhenNotTargeting) {
+ auto owner = User(mDispatcher, 10, 11);
+ auto window = owner.createWindow();
+
+ auto rando = User(mDispatcher, 20, 21);
+ auto randosSpy = rando.createWindow();
+ randosSpy->setSpy(true);
+ randosSpy->setTrustedOverlay(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {randosSpy, window}}});
+
+ // A user that has injection permission can inject into any window.
+ EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT));
+ randosSpy->consumeMotionDown();
+ window->consumeMotionDown();
+
+ setFocusedWindow(randosSpy);
+ randosSpy->consumeFocusEvent(true);
+
+ EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher));
+ randosSpy->consumeKeyDown(ADISPLAY_ID_NONE);
+ window->assertNoEvents();
+}
+
+TEST_F(InputDispatcherTargetedInjectionTest, CanGenerateActionOutsideToOtherUids) {
+ auto owner = User(mDispatcher, 10, 11);
+ auto window = owner.createWindow();
+
+ auto rando = User(mDispatcher, 20, 21);
+ auto randosWindow = rando.createWindow();
+ randosWindow->setFrame(Rect{-10, -10, -5, -5});
+ randosWindow->setWatchOutsideTouch(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {randosWindow, window}}});
+
+ // We allow generation of ACTION_OUTSIDE events into windows owned by different uids.
+ EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
+ owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
+ window->consumeMotionDown();
+ randosWindow->consumeMotionOutside();
+}
+
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
index e378096..0062f42 100644
--- a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
+++ b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
@@ -19,6 +19,7 @@
#include <gtest/gtest.h>
#include <gui/constants.h>
#include <linux/input.h>
+#include <thread>
#include "TestInputListener.h"
@@ -547,6 +548,27 @@
mBlocker->notifyMotion(&args);
}
+/**
+ * Call dump, and on another thread, try to send some motions. The blocker should
+ * not crash. On 2022 hardware, this test requires ~ 13K executions (about 20 seconds) to reproduce
+ * the original bug. This is meant to be run with "--gtest_repeat=100000 --gtest_break_on_failure"
+ * options
+ */
+TEST_F(UnwantedInteractionBlockerTest, DumpCanBeAccessedOnAnotherThread) {
+ mBlocker->notifyInputDevicesChanged({generateTestDeviceInfo()});
+ NotifyMotionArgs args1 = generateMotionArgs(0 /*downTime*/, 0 /*eventTime*/, DOWN, {{1, 2, 3}});
+ mBlocker->notifyMotion(&args1);
+ std::thread dumpThread([this]() {
+ std::string dump;
+ mBlocker->dump(dump);
+ });
+ NotifyMotionArgs args2 = generateMotionArgs(0 /*downTime*/, 1 /*eventTime*/, MOVE, {{4, 5, 6}});
+ mBlocker->notifyMotion(&args2);
+ NotifyMotionArgs args3 = generateMotionArgs(0 /*downTime*/, 2 /*eventTime*/, UP, {{4, 5, 6}});
+ mBlocker->notifyMotion(&args3);
+ dumpThread.join();
+}
+
using UnwantedInteractionBlockerTestDeathTest = UnwantedInteractionBlockerTest;
/**
diff --git a/services/sensorservice/SensorDirectConnection.cpp b/services/sensorservice/SensorDirectConnection.cpp
index fae16f6..2dd12e9 100644
--- a/services/sensorservice/SensorDirectConnection.cpp
+++ b/services/sensorservice/SensorDirectConnection.cpp
@@ -157,7 +157,7 @@
}
const Sensor& s = si->getSensor();
- if (!SensorService::canAccessSensor(s, "config direct channel", mOpPackageName)) {
+ if (!mService->canAccessSensor(s, "config direct channel", mOpPackageName)) {
return PERMISSION_DENIED;
}
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index 6948895..f06f947 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -162,7 +162,8 @@
Mutex::Autolock _l(mConnectionLock);
sp<SensorInterface> si = mService->getSensorInterfaceFromHandle(handle);
if (si == nullptr ||
- !canAccessSensor(si->getSensor(), "Add to SensorEventConnection: ", mOpPackageName) ||
+ !mService->canAccessSensor(si->getSensor(), "Add to SensorEventConnection: ",
+ mOpPackageName) ||
mSensorInfo.count(handle) > 0) {
return false;
}
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 88cf5ab..948692b 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -814,6 +814,12 @@
return handleResetUidState(args, err);
} else if (args[0] == String16("get-uid-state")) {
return handleGetUidState(args, out, err);
+ } else if (args[0] == String16("unrestrict-ht")) {
+ mHtRestricted = false;
+ return NO_ERROR;
+ } else if (args[0] == String16("restrict-ht")) {
+ mHtRestricted = true;
+ return NO_ERROR;
} else if (args.size() == 1 && args[0] == String16("help")) {
printHelp(out);
return NO_ERROR;
@@ -1338,11 +1344,11 @@
Vector<Sensor> SensorService::getDynamicSensorList(const String16& opPackageName) {
Vector<Sensor> accessibleSensorList;
mSensors.forEachSensor(
- [&opPackageName, &accessibleSensorList] (const Sensor& sensor) -> bool {
+ [this, &opPackageName, &accessibleSensorList] (const Sensor& sensor) -> bool {
if (sensor.isDynamicSensor()) {
- if (canAccessSensor(sensor, "getDynamicSensorList", opPackageName)) {
+ if (canAccessSensor(sensor, "can't see", opPackageName)) {
accessibleSensorList.add(sensor);
- } else {
+ } else if (sensor.getType() != SENSOR_TYPE_HEAD_TRACKER) {
ALOGI("Skipped sensor %s because it requires permission %s and app op %" PRId32,
sensor.getName().string(),
sensor.getRequiredPermission().string(),
@@ -1989,6 +1995,20 @@
bool SensorService::canAccessSensor(const Sensor& sensor, const char* operation,
const String16& opPackageName) {
+ // Special case for Head Tracker sensor type: currently restricted to system usage only, unless
+ // the restriction is specially lifted for testing
+ if (sensor.getType() == SENSOR_TYPE_HEAD_TRACKER &&
+ !isAudioServerOrSystemServerUid(IPCThreadState::self()->getCallingUid())) {
+ if (!mHtRestricted) {
+ ALOGI("Permitting access to HT sensor type outside system (%s)",
+ String8(opPackageName).string());
+ } else {
+ ALOGW("%s %s a sensor (%s) as a non-system client", String8(opPackageName).string(),
+ operation, sensor.getName().string());
+ return false;
+ }
+ }
+
// Check if a permission is required for this sensor
if (sensor.getRequiredPermission().length() <= 0) {
return true;
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index b18d204..234dc9c 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -373,7 +373,7 @@
status_t cleanupWithoutDisableLocked(const sp<SensorEventConnection>& connection, int handle);
void cleanupAutoDisabledSensorLocked(const sp<SensorEventConnection>& connection,
sensors_event_t const* buffer, const int count);
- static bool canAccessSensor(const Sensor& sensor, const char* operation,
+ bool canAccessSensor(const Sensor& sensor, const char* operation,
const String16& opPackageName);
static bool hasPermissionForSensor(const Sensor& sensor);
static int getTargetSdkVersion(const String16& opPackageName);
@@ -492,6 +492,10 @@
std::unordered_map<int, SensorServiceUtil::RecentEventLogger*> mRecentEvent;
Mode mCurrentOperatingMode;
+ // true if the head tracker sensor type is currently restricted to system usage only
+ // (can only be unrestricted for testing, via shell cmd)
+ bool mHtRestricted = true;
+
// This packagaName is set when SensorService is in RESTRICTED or DATA_INJECTION mode. Only
// applications with this packageName are allowed to activate/deactivate or call flush on
// sensors. To run CTS this is can be set to ".cts." and only CTS tests will get access to
diff --git a/services/surfaceflinger/BackgroundExecutor.cpp b/services/surfaceflinger/BackgroundExecutor.cpp
index de8e6b3..a15de2b 100644
--- a/services/surfaceflinger/BackgroundExecutor.cpp
+++ b/services/surfaceflinger/BackgroundExecutor.cpp
@@ -19,6 +19,8 @@
#define LOG_TAG "BackgroundExecutor"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <utils/Log.h>
+
#include "BackgroundExecutor.h"
namespace android {
@@ -27,41 +29,49 @@
BackgroundExecutor::BackgroundExecutor() : Singleton<BackgroundExecutor>() {
mThread = std::thread([&]() {
- bool done = false;
- while (!done) {
- std::vector<std::function<void()>> tasks;
- {
- std::unique_lock lock(mMutex);
- android::base::ScopedLockAssertion assumeLock(mMutex);
- mWorkAvailableCv.wait(lock,
- [&]() REQUIRES(mMutex) { return mDone || !mTasks.empty(); });
- tasks = std::move(mTasks);
- mTasks.clear();
- done = mDone;
- } // unlock mMutex
+ LOG_ALWAYS_FATAL_IF(sem_init(&mSemaphore, 0, 0), "sem_init failed");
+ while (!mDone) {
+ LOG_ALWAYS_FATAL_IF(sem_wait(&mSemaphore), "sem_wait failed (%d)", errno);
- for (auto& task : tasks) {
- task();
+ ftl::SmallVector<Work*, 10> workItems;
+
+ Work* work = mWorks.pop();
+ while (work) {
+ workItems.push_back(work);
+ work = mWorks.pop();
+ }
+
+ // Sequence numbers are guaranteed to be in intended order, as we assume a single
+ // producer and single consumer.
+ std::stable_sort(workItems.begin(), workItems.end(), [](Work* left, Work* right) {
+ return left->sequence < right->sequence;
+ });
+ for (Work* work : workItems) {
+ for (auto& task : work->tasks) {
+ task();
+ }
+ delete work;
}
}
});
}
BackgroundExecutor::~BackgroundExecutor() {
- {
- std::scoped_lock lock(mMutex);
- mDone = true;
- mWorkAvailableCv.notify_all();
- }
+ mDone = true;
+ LOG_ALWAYS_FATAL_IF(sem_post(&mSemaphore), "sem_post failed");
if (mThread.joinable()) {
mThread.join();
+ LOG_ALWAYS_FATAL_IF(sem_destroy(&mSemaphore), "sem_destroy failed");
}
}
-void BackgroundExecutor::execute(std::function<void()> task) {
- std::scoped_lock lock(mMutex);
- mTasks.emplace_back(std::move(task));
- mWorkAvailableCv.notify_all();
+void BackgroundExecutor::sendCallbacks(Callbacks&& tasks) {
+ Work* work = new Work();
+ work->sequence = mSequence;
+ work->tasks = std::move(tasks);
+ mWorks.push(work);
+ mSequence++;
+ LOG_ALWAYS_FATAL_IF(sem_post(&mSemaphore), "sem_post failed");
}
} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/BackgroundExecutor.h b/services/surfaceflinger/BackgroundExecutor.h
index 6db7dda..eeaf3bd 100644
--- a/services/surfaceflinger/BackgroundExecutor.h
+++ b/services/surfaceflinger/BackgroundExecutor.h
@@ -16,9 +16,11 @@
#pragma once
+#include <Tracing/LocklessStack.h>
#include <android-base/thread_annotations.h>
+#include <ftl/small_vector.h>
+#include <semaphore.h>
#include <utils/Singleton.h>
-#include <condition_variable>
#include <mutex>
#include <queue>
#include <thread>
@@ -30,13 +32,26 @@
public:
BackgroundExecutor();
~BackgroundExecutor();
- void execute(std::function<void()>);
+ using Callbacks = ftl::SmallVector<std::function<void()>, 10>;
+ // Queues callbacks onto a work queue to be executed by a background thread.
+ // Note that this is not thread-safe - a single producer is assumed.
+ void sendCallbacks(Callbacks&& tasks);
private:
- std::mutex mMutex;
- std::condition_variable mWorkAvailableCv GUARDED_BY(mMutex);
- bool mDone GUARDED_BY(mMutex) = false;
- std::vector<std::function<void()>> mTasks GUARDED_BY(mMutex);
+ sem_t mSemaphore;
+ std::atomic_bool mDone = false;
+
+ // Sequence number for work items.
+ // Work items are batched by sequence number. Work items for earlier sequence numbers are
+ // executed first. Work items with the same sequence number are executed in the same order they
+ // were added to the stack (meaning the stack must reverse the order after popping from the
+ // queue)
+ int32_t mSequence = 0;
+ struct Work {
+ int32_t sequence = 0;
+ Callbacks tasks;
+ };
+ LocklessStack<Work> mWorks;
std::thread mThread;
};
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 635b088..f8c53c3 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -315,11 +315,7 @@
compositionState->sidebandStreamHasFrame = false;
}
-bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) {
- if (mBufferInfo.mBuffer != nullptr) {
- Mutex::Autolock lock(mFrameEventHistoryMutex);
- mFrameEventHistory.addPreComposition(mCurrentFrameNumber, refreshStartTime);
- }
+bool BufferLayer::onPreComposition(nsecs_t) {
return hasReadyFrame();
}
namespace {
@@ -365,12 +361,7 @@
mAlreadyDisplayedThisCompose = false;
// Update mFrameEventHistory.
- {
- Mutex::Autolock lock(mFrameEventHistoryMutex);
- mFrameEventHistory.addPostComposition(mCurrentFrameNumber, glDoneFence, presentFence,
- compositorTiming);
- finalizeFrameEventHistory(glDoneFence, compositorTiming);
- }
+ finalizeFrameEventHistory(glDoneFence, compositorTiming);
// Update mFrameTracker.
nsecs_t desiredPresentTime = mBufferInfo.mDesiredPresentTime;
@@ -500,7 +491,7 @@
return false;
}
- err = updateFrameNumber(latchTime);
+ err = updateFrameNumber();
if (err != NO_ERROR) {
return false;
}
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 3e70493..4c70eb5 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -192,7 +192,7 @@
nsecs_t expectedPresentTime) = 0;
virtual status_t updateActiveBuffer() = 0;
- virtual status_t updateFrameNumber(nsecs_t latchTime) = 0;
+ virtual status_t updateFrameNumber() = 0;
// We generate InputWindowHandles for all non-cursor buffered layers regardless of whether they
// have an InputChannel. This is to enable the InputDispatcher to do PID based occlusion
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 9ae45fc..7361a4f 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -471,18 +471,6 @@
}
}
-void BufferLayerConsumer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
- FrameEventHistoryDelta* outDelta) {
- Mutex::Autolock lock(mMutex);
-
- if (mAbandoned) {
- // Nothing to do if we're already abandoned.
- return;
- }
-
- mLayer->addAndGetFrameTimestamps(newTimestamps, outDelta);
-}
-
void BufferLayerConsumer::abandonLocked() {
BLC_LOGV("abandonLocked");
mCurrentTextureBuffer = nullptr;
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index 9ed80b4..23ad2a3 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -236,8 +236,7 @@
// IConsumerListener interface
void onDisconnect() override;
void onSidebandStreamChanged() override;
- void addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
- FrameEventHistoryDelta* outDelta) override;
+ void addAndGetFrameTimestamps(const NewFrameEventsEntry*, FrameEventHistoryDelta*) override {}
// computeCurrentTransformMatrixLocked computes the transform matrix for the
// current texture. It uses mCurrentTransform and the current GraphicBuffer
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 926aa1d..bee4de3 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -48,9 +48,8 @@
// Interface implementation for Layer
// -----------------------------------------------------------------------
-void BufferQueueLayer::onLayerDisplayed(
- std::shared_future<renderengine::RenderEngineResult> futureRenderEngineResult) {
- sp<Fence> releaseFence = new Fence(dup(futureRenderEngineResult.get().drawFence));
+void BufferQueueLayer::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFenceResult) {
+ const sp<Fence> releaseFence = futureFenceResult.get().value_or(Fence::NO_FENCE);
mConsumer->setReleaseFence(releaseFence);
// Prevent tracing the same release multiple times.
@@ -67,20 +66,10 @@
mConsumer->setTransformHint(mTransformHint);
}
-void BufferQueueLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
+void BufferQueueLayer::releasePendingBuffer(nsecs_t) {
if (!mConsumer->releasePendingBuffer()) {
return;
}
-
- auto releaseFenceTime = std::make_shared<FenceTime>(mConsumer->getPrevFinalReleaseFence());
- mReleaseTimeline.updateSignalTimes();
- mReleaseTimeline.push(releaseFenceTime);
-
- Mutex::Autolock lock(mFrameEventHistoryMutex);
- if (mPreviousFrameNumber != 0) {
- mFrameEventHistory.addRelease(mPreviousFrameNumber, dequeueReadyTime,
- std::move(releaseFenceTime));
- }
}
void BufferQueueLayer::setDefaultBufferSize(uint32_t w, uint32_t h) {
@@ -320,14 +309,9 @@
return NO_ERROR;
}
-status_t BufferQueueLayer::updateFrameNumber(nsecs_t latchTime) {
+status_t BufferQueueLayer::updateFrameNumber() {
mPreviousFrameNumber = mCurrentFrameNumber;
mCurrentFrameNumber = mConsumer->getFrameNumber();
-
- {
- Mutex::Autolock lock(mFrameEventHistoryMutex);
- mFrameEventHistory.addLatch(mCurrentFrameNumber, latchTime);
- }
return NO_ERROR;
}
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index c6e0727..e1c80d5 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -42,8 +42,7 @@
// Implements Layer.
const char* getType() const override { return "BufferQueueLayer"; }
- void onLayerDisplayed(
- std::shared_future<renderengine::RenderEngineResult> futureRenderEngineResult) override;
+ void onLayerDisplayed(ftl::SharedFuture<FenceResult>) override;
// If a buffer was replaced this frame, release the former buffer
void releasePendingBuffer(nsecs_t dequeueReadyTime) override;
@@ -103,7 +102,7 @@
nsecs_t expectedPresentTime) override;
status_t updateActiveBuffer() override;
- status_t updateFrameNumber(nsecs_t latchTime) override;
+ status_t updateFrameNumber() override;
void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& frameTimelineInfo) override;
sp<Layer> createClone() override;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index c5d7a60..1a5b925 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -73,8 +73,7 @@
// -----------------------------------------------------------------------
// Interface implementation for Layer
// -----------------------------------------------------------------------
-void BufferStateLayer::onLayerDisplayed(
- std::shared_future<renderengine::RenderEngineResult> futureRenderEngineResult) {
+void BufferStateLayer::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFenceResult) {
// If we are displayed on multiple displays in a single composition cycle then we would
// need to do careful tracking to enable the use of the mLastClientCompositionFence.
// For example we can only use it if all the displays are client comp, and we need
@@ -118,7 +117,7 @@
if (ch != nullptr) {
ch->previousReleaseCallbackId = mPreviousReleaseCallbackId;
- ch->previousReleaseFences.emplace_back(futureRenderEngineResult);
+ ch->previousReleaseFences.emplace_back(std::move(futureFenceResult));
ch->name = mName;
}
}
@@ -179,15 +178,6 @@
}
mDrawingState.callbackHandles = {};
-
- std::shared_ptr<FenceTime> releaseFenceTime = std::make_shared<FenceTime>(releaseFence);
- {
- Mutex::Autolock lock(mFrameEventHistoryMutex);
- if (mPreviousFrameNumber != 0) {
- mFrameEventHistory.addRelease(mPreviousFrameNumber, dequeueReadyTime,
- std::move(releaseFenceTime));
- }
- }
}
void BufferStateLayer::finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& glDoneFence,
@@ -347,19 +337,6 @@
return true;
}
-bool BufferStateLayer::addFrameEvent(const sp<Fence>& acquireFence, nsecs_t postedTime,
- nsecs_t desiredPresentTime) {
- Mutex::Autolock lock(mFrameEventHistoryMutex);
- mAcquireTimeline.updateSignalTimes();
- std::shared_ptr<FenceTime> acquireFenceTime =
- std::make_shared<FenceTime>((acquireFence ? acquireFence : Fence::NO_FENCE));
- NewFrameEventsEntry newTimestamps = {mDrawingState.frameNumber, postedTime, desiredPresentTime,
- acquireFenceTime};
- mFrameEventHistory.setProducerWantsEvents();
- mFrameEventHistory.addQueue(newTimestamps);
- return true;
-}
-
bool BufferStateLayer::setBuffer(std::shared_ptr<renderengine::ExternalTexture>& buffer,
const BufferData& bufferData, nsecs_t postTime,
nsecs_t desiredPresentTime, bool isAutoTimestamp,
@@ -446,8 +423,6 @@
using LayerUpdateType = scheduler::LayerHistory::LayerUpdateType;
mFlinger->mScheduler->recordLayerHistory(this, presentTime, LayerUpdateType::Buffer);
- addFrameEvent(mDrawingState.acquireFence, postTime, isAutoTimestamp ? 0 : desiredPresentTime);
-
setFrameTimelineVsyncForBufferTransaction(info, postTime);
if (dequeueTime && *dequeueTime != 0) {
@@ -727,14 +702,10 @@
return NO_ERROR;
}
-status_t BufferStateLayer::updateFrameNumber(nsecs_t latchTime) {
+status_t BufferStateLayer::updateFrameNumber() {
// TODO(marissaw): support frame history events
mPreviousFrameNumber = mCurrentFrameNumber;
mCurrentFrameNumber = mDrawingState.frameNumber;
- {
- Mutex::Autolock lock(mFrameEventHistoryMutex);
- mFrameEventHistory.addLatch(mCurrentFrameNumber, latchTime);
- }
return NO_ERROR;
}
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 8a696f1..3f0dbe4 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -39,8 +39,7 @@
// Implements Layer.
const char* getType() const override { return "BufferStateLayer"; }
- void onLayerDisplayed(
- std::shared_future<renderengine::RenderEngineResult> futureRenderEngineResult) override;
+ void onLayerDisplayed(ftl::SharedFuture<FenceResult>) override;
void releasePendingBuffer(nsecs_t dequeueReadyTime) override;
@@ -67,8 +66,6 @@
bool setApi(int32_t api) override;
bool setSidebandStream(const sp<NativeHandle>& sidebandStream) override;
bool setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& handles) override;
- bool addFrameEvent(const sp<Fence>& acquireFence, nsecs_t postedTime,
- nsecs_t requestedPresentTime) override;
bool setPosition(float /*x*/, float /*y*/) override;
bool setMatrix(const layer_state_t::matrix22_t& /*matrix*/);
@@ -125,7 +122,7 @@
nsecs_t expectedPresentTime) override;
status_t updateActiveBuffer() override;
- status_t updateFrameNumber(nsecs_t latchTime) override;
+ status_t updateFrameNumber() override;
sp<Layer> createClone() override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/FenceResult.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/FenceResult.h
new file mode 100644
index 0000000..0ce263b
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/FenceResult.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/expected.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+// TODO(b/232535621): Pull this file to <ui/FenceResult.h> so that RenderEngine::drawLayers returns
+// FenceResult rather than RenderEngineResult.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+#include <renderengine/RenderEngine.h>
+#pragma clang diagnostic pop
+
+namespace android {
+
+class Fence;
+
+using FenceResult = base::expected<sp<Fence>, status_t>;
+
+// TODO(b/232535621): Prevent base::unexpected(NO_ERROR) from being a valid FenceResult.
+inline status_t fenceStatus(const FenceResult& fenceResult) {
+ return fenceResult.ok() ? NO_ERROR : fenceResult.error();
+}
+
+inline FenceResult toFenceResult(renderengine::RenderEngineResult&& result) {
+ if (auto [status, fence] = std::move(result); fence.ok()) {
+ return sp<Fence>::make(std::move(fence));
+ } else {
+ return base::unexpected(status);
+ }
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index e77e155..ec610c1 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -16,22 +16,23 @@
#pragma once
-#include <future>
#include <optional>
#include <ostream>
#include <unordered_set>
+#include <compositionengine/FenceResult.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 <renderengine/LayerSettings.h>
-#include <renderengine/RenderEngine.h>
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
+#include <ftl/future.h>
#include <utils/RefBase.h>
#include <utils/Timers.h>
@@ -156,7 +157,7 @@
ClientCompositionTargetSettings&) = 0;
// Called after the layer is displayed to update the presentation fence
- virtual void onLayerDisplayed(std::shared_future<renderengine::RenderEngineResult>) = 0;
+ virtual void onLayerDisplayed(ftl::SharedFuture<FenceResult>) = 0;
// Gets some kind of identifier for the layer for debug purposes.
virtual const char* getDebugName() const = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index c65d467..7709b96 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -164,6 +164,9 @@
bool treat170mAsSrgb = false;
+ uint64_t lastOutputLayerHash = 0;
+ uint64_t outputLayerHash = 0;
+
// Debugging
void dump(std::string& result) const;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index ee0c53d..1c5c10f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -49,7 +49,7 @@
std::vector<compositionengine::LayerFE::LayerSettings>(
compositionengine::LayerFE::ClientCompositionTargetSettings&));
- MOCK_METHOD1(onLayerDisplayed, void(std::shared_future<renderengine::RenderEngineResult>));
+ MOCK_METHOD(void, onLayerDisplayed, (ftl::SharedFuture<FenceResult>), (override));
MOCK_CONST_METHOD0(getDebugName, const char*());
MOCK_CONST_METHOD0(getSequence, int32_t());
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 4c30f99..aac478d 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -763,6 +763,7 @@
bool includeGeometry = refreshArgs.updatingGeometryThisFrame;
uint32_t z = 0;
bool overrideZ = false;
+ uint64_t outputLayerHash = 0;
for (auto* layer : getOutputLayersOrderedByZ()) {
if (layer == peekThroughLayer) {
// No longer needed, although it should not show up again, so
@@ -789,6 +790,10 @@
constexpr bool isPeekingThrough = true;
peekThroughLayer->writeStateToHWC(includeGeometry, false, z++, overrideZ,
isPeekingThrough);
+ outputLayerHash ^= android::hashCombine(
+ reinterpret_cast<uint64_t>(&peekThroughLayer->getLayerFE()),
+ z, includeGeometry, overrideZ, isPeekingThrough,
+ peekThroughLayer->requiresClientComposition());
}
previousOverride = overrideInfo.buffer->getBuffer();
@@ -797,7 +802,14 @@
constexpr bool isPeekingThrough = false;
layer->writeStateToHWC(includeGeometry, skipLayer, z++, overrideZ, isPeekingThrough);
+ if (!skipLayer) {
+ outputLayerHash ^= android::hashCombine(
+ reinterpret_cast<uint64_t>(&layer->getLayerFE()),
+ z, includeGeometry, overrideZ, isPeekingThrough,
+ layer->requiresClientComposition());
+ }
}
+ editState().outputLayerHash = outputLayerHash;
}
compositionengine::OutputLayer* Output::findLayerRequestingBackgroundComposition() const {
@@ -1245,34 +1257,31 @@
// probably to encapsulate the output buffer into a structure that dispatches resource cleanup
// over to RenderEngine, in which case this flag can be removed from the drawLayers interface.
const bool useFramebufferCache = outputState.layerFilter.toInternalDisplay;
- auto [status, drawFence] =
- renderEngine
- .drawLayers(clientCompositionDisplay, clientRenderEngineLayers, tex,
- useFramebufferCache, std::move(fd))
- .get();
- if (status != NO_ERROR && mClientCompositionRequestCache) {
+ auto fenceResult =
+ toFenceResult(renderEngine
+ .drawLayers(clientCompositionDisplay, clientRenderEngineLayers,
+ tex, useFramebufferCache, std::move(fd))
+ .get());
+
+ if (mClientCompositionRequestCache && fenceStatus(fenceResult) != NO_ERROR) {
// If rendering was not successful, remove the request from the cache.
mClientCompositionRequestCache->remove(tex->getBuffer()->getId());
}
- auto& timeStats = getCompositionEngine().getTimeStats();
- if (drawFence.get() < 0) {
- timeStats.recordRenderEngineDuration(renderEngineStart, systemTime());
+ const auto fence = std::move(fenceResult).value_or(Fence::NO_FENCE);
+
+ if (auto& timeStats = getCompositionEngine().getTimeStats(); fence->isValid()) {
+ timeStats.recordRenderEngineDuration(renderEngineStart, std::make_shared<FenceTime>(fence));
} else {
- timeStats.recordRenderEngineDuration(renderEngineStart,
- std::make_shared<FenceTime>(
- new Fence(dup(drawFence.get()))));
+ timeStats.recordRenderEngineDuration(renderEngineStart, systemTime());
}
- if (clientCompositionLayersFE.size() > 0) {
- sp<Fence> clientCompFence = new Fence(dup(drawFence.get()));
- for (auto clientComposedLayer : clientCompositionLayersFE) {
- clientComposedLayer->setWasClientComposed(clientCompFence);
- }
+ for (auto* clientComposedLayer : clientCompositionLayersFE) {
+ clientComposedLayer->setWasClientComposed(fence);
}
- return std::move(drawFence);
+ return base::unique_fd(fence->dup());
}
std::vector<LayerFE::LayerSettings> Output::generateClientCompositionRequests(
@@ -1356,7 +1365,10 @@
}
}
- outLayerFEs.push_back(&layerFE);
+ if (clientComposition) {
+ outLayerFEs.push_back(&layerFE);
+ }
+
clientCompositionLayers.insert(clientCompositionLayers.end(),
std::make_move_iterator(results.begin()),
std::make_move_iterator(results.end()));
@@ -1429,19 +1441,15 @@
Fence::merge("LayerRelease", releaseFence, frame.clientTargetAcquireFence);
}
layer->getLayerFE().onLayerDisplayed(
- ftl::yield<renderengine::RenderEngineResult>(
- {NO_ERROR, base::unique_fd(releaseFence->dup())})
- .share());
+ ftl::yield<FenceResult>(std::move(releaseFence)).share());
}
// We've got a list of layers needing fences, that are disjoint with
// OutputLayersOrderedByZ. The best we can do is to
// supply them with the present fence.
for (auto& weakLayer : mReleasedLayers) {
- if (auto layer = weakLayer.promote(); layer != nullptr) {
- layer->onLayerDisplayed(ftl::yield<renderengine::RenderEngineResult>(
- {NO_ERROR, base::unique_fd(frame.presentFence->dup())})
- .share());
+ if (const auto layer = weakLayer.promote()) {
+ layer->onLayerDisplayed(ftl::yield<FenceResult>(frame.presentFence).share());
}
}
@@ -1493,6 +1501,10 @@
}
bool Output::canPredictCompositionStrategy(const CompositionRefreshArgs& refreshArgs) {
+ uint64_t lastOutputLayerHash = getState().lastOutputLayerHash;
+ uint64_t outputLayerHash = getState().outputLayerHash;
+ editState().lastOutputLayerHash = outputLayerHash;
+
if (!getState().isEnabled || !mHwComposerAsyncWorker) {
ALOGV("canPredictCompositionStrategy disabled");
return false;
@@ -1513,6 +1525,11 @@
return false;
}
+ if (lastOutputLayerHash != outputLayerHash) {
+ ALOGV("canPredictCompositionStrategy output layers changed");
+ return false;
+ }
+
// If no layer uses clientComposition, then don't predict composition strategy
// because we have less work to do in parallel.
if (!anyLayersRequireClientComposition()) {
@@ -1520,12 +1537,7 @@
return false;
}
- if (!refreshArgs.updatingOutputGeometryThisFrame) {
- return true;
- }
-
- ALOGV("canPredictCompositionStrategy updatingOutputGeometryThisFrame");
- return false;
+ return true;
}
bool Output::anyLayersRequireClientComposition() const {
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index aaca4fe..d15b0a7 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -271,13 +271,16 @@
bufferFence.reset(texture->getReadyFence()->dup());
}
- auto [status, drawFence] = renderEngine
- .drawLayers(displaySettings, layerSettings, texture->get(),
- false, std::move(bufferFence))
- .get();
+ constexpr bool kUseFramebufferCache = false;
- if (status == NO_ERROR) {
- mDrawFence = new Fence(drawFence.release());
+ auto fenceResult =
+ toFenceResult(renderEngine
+ .drawLayers(displaySettings, layerSettings, texture->get(),
+ kUseFramebufferCache, std::move(bufferFence))
+ .get());
+
+ if (fenceStatus(fenceResult) == NO_ERROR) {
+ mDrawFence = std::move(fenceResult).value_or(Fence::NO_FENCE);
mOutputSpace = outputState.framebufferSpace;
mTexture = texture;
mTexture->setReadyFence(mDrawFence);
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index 8d26747..0918510 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -401,19 +401,6 @@
return true;
}
-namespace {
-bool isDisplayDecoration(const CachedSet& cachedSet) {
- return cachedSet.getLayerCount() == 1 &&
- cachedSet.getFirstLayer()
- .getState()
- ->getOutputLayer()
- ->getLayerFE()
- .getCompositionState()
- ->compositionType ==
- aidl::android::hardware::graphics::composer3::Composition::DISPLAY_DECORATION;
-}
-} // namespace
-
std::vector<Flattener::Run> Flattener::findCandidateRuns(time_point now) const {
ATRACE_CALL();
std::vector<Run> runs;
@@ -437,7 +424,7 @@
}
if (layerIsInactive && (firstLayer || runHasFirstLayer || !layerHasBlur) &&
- !currentSet->hasUnsupportedDataspace() && !isDisplayDecoration(*currentSet)) {
+ !currentSet->hasUnsupportedDataspace()) {
if (isPartOfRun) {
builder.increment();
} else {
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index ff2aa15..9b12b08 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -84,9 +84,9 @@
MOCK_METHOD4(setDisplayContentSamplingEnabled, status_t(HalDisplayId, bool, uint8_t, uint64_t));
MOCK_METHOD4(getDisplayedContentSample,
status_t(HalDisplayId, uint64_t, uint64_t, DisplayedFrameStats*));
- MOCK_METHOD4(setDisplayBrightness,
- std::future<status_t>(PhysicalDisplayId, float, float,
- const Hwc2::Composer::DisplayBrightnessOptions&));
+ 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,
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 862ab1d..063726b 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -850,14 +850,20 @@
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,
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,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer3.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
injectOutputLayer(layer1);
injectOutputLayer(layer2);
@@ -884,14 +890,20 @@
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,
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,
writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer3.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
injectOutputLayer(layer1);
injectOutputLayer(layer2);
@@ -917,14 +929,20 @@
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,
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,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer3.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
injectOutputLayer(layer1);
injectOutputLayer(layer2);
@@ -950,6 +968,8 @@
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(*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));
@@ -957,6 +977,9 @@
EXPECT_CALL(*layer0.outputLayer,
writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer0.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
+
// After calling planComposition (which clears overrideInfo), this test sets
// layer3 to be the peekThroughLayer for layer1 and layer2. As a result, it
@@ -966,12 +989,18 @@
writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
/*zIsOverridden*/ true, /*isPeekingThrough*/
true));
+ EXPECT_CALL(*layer3.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
EXPECT_CALL(*layer1.outputLayer,
writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
/*zIsOverridden*/ true, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer1.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
EXPECT_CALL(*layer2.outputLayer,
writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ true, z++,
/*zIsOverridden*/ true, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer2.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
injectOutputLayer(layer0);
injectOutputLayer(layer1);
@@ -3171,9 +3200,9 @@
mOutput.mState.isEnabled = true;
// Create three unique fence instances
- sp<Fence> layer1Fence = new Fence();
- sp<Fence> layer2Fence = new Fence();
- sp<Fence> layer3Fence = new Fence();
+ sp<Fence> layer1Fence = sp<Fence>::make();
+ sp<Fence> layer2Fence = sp<Fence>::make();
+ sp<Fence> layer3Fence = sp<Fence>::make();
Output::FrameFences frameFences;
frameFences.layerFences.emplace(&mLayer1.hwc2Layer, layer1Fence);
@@ -3188,23 +3217,17 @@
// are passed. This happens to work with the current implementation, but
// would not survive certain calls like Fence::merge() which would return a
// new instance.
- base::unique_fd layer1FD(layer1Fence->dup());
- base::unique_fd layer2FD(layer2Fence->dup());
- base::unique_fd layer3FD(layer3Fence->dup());
EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed(_))
- .WillOnce([&layer1FD](std::shared_future<renderengine::RenderEngineResult>
- futureRenderEngineResult) {
- EXPECT_EQ(layer1FD, futureRenderEngineResult.get().drawFence);
+ .WillOnce([&layer1Fence](ftl::SharedFuture<FenceResult> futureFenceResult) {
+ EXPECT_EQ(FenceResult(layer1Fence), futureFenceResult.get());
});
EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed(_))
- .WillOnce([&layer2FD](std::shared_future<renderengine::RenderEngineResult>
- futureRenderEngineResult) {
- EXPECT_EQ(layer2FD, futureRenderEngineResult.get().drawFence);
+ .WillOnce([&layer2Fence](ftl::SharedFuture<FenceResult> futureFenceResult) {
+ EXPECT_EQ(FenceResult(layer2Fence), futureFenceResult.get());
});
EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed(_))
- .WillOnce([&layer3FD](std::shared_future<renderengine::RenderEngineResult>
- futureRenderEngineResult) {
- EXPECT_EQ(layer3FD, futureRenderEngineResult.get().drawFence);
+ .WillOnce([&layer3Fence](ftl::SharedFuture<FenceResult> futureFenceResult) {
+ EXPECT_EQ(FenceResult(layer3Fence), futureFenceResult.get());
});
mOutput.postFramebuffer();
@@ -3214,15 +3237,11 @@
mOutput.mState.isEnabled = true;
mOutput.mState.usesClientComposition = true;
- sp<Fence> clientTargetAcquireFence = new Fence();
- sp<Fence> layer1Fence = new Fence();
- sp<Fence> layer2Fence = new Fence();
- sp<Fence> layer3Fence = new Fence();
Output::FrameFences frameFences;
- frameFences.clientTargetAcquireFence = clientTargetAcquireFence;
- frameFences.layerFences.emplace(&mLayer1.hwc2Layer, layer1Fence);
- frameFences.layerFences.emplace(&mLayer2.hwc2Layer, layer2Fence);
- frameFences.layerFences.emplace(&mLayer3.hwc2Layer, layer3Fence);
+ frameFences.clientTargetAcquireFence = sp<Fence>::make();
+ frameFences.layerFences.emplace(&mLayer1.hwc2Layer, sp<Fence>::make());
+ frameFences.layerFences.emplace(&mLayer2.hwc2Layer, sp<Fence>::make());
+ frameFences.layerFences.emplace(&mLayer3.hwc2Layer, sp<Fence>::make());
EXPECT_CALL(*mRenderSurface, flip());
EXPECT_CALL(mOutput, presentAndGetFrameFences()).WillOnce(Return(frameFences));
@@ -3256,7 +3275,7 @@
mOutput.setReleasedLayers(std::move(layers));
// Set up a fake present fence
- sp<Fence> presentFence = new Fence();
+ sp<Fence> presentFence = sp<Fence>::make();
Output::FrameFences frameFences;
frameFences.presentFence = presentFence;
@@ -3265,21 +3284,17 @@
EXPECT_CALL(*mRenderSurface, onPresentDisplayCompleted());
// Each released layer should be given the presentFence.
- base::unique_fd layerFD(presentFence.get()->dup());
EXPECT_CALL(*releasedLayer1, onLayerDisplayed(_))
- .WillOnce([&layerFD](std::shared_future<renderengine::RenderEngineResult>
- futureRenderEngineResult) {
- EXPECT_EQ(layerFD, futureRenderEngineResult.get().drawFence);
+ .WillOnce([&presentFence](ftl::SharedFuture<FenceResult> futureFenceResult) {
+ EXPECT_EQ(FenceResult(presentFence), futureFenceResult.get());
});
EXPECT_CALL(*releasedLayer2, onLayerDisplayed(_))
- .WillOnce([&layerFD](std::shared_future<renderengine::RenderEngineResult>
- futureRenderEngineResult) {
- EXPECT_EQ(layerFD, futureRenderEngineResult.get().drawFence);
+ .WillOnce([&presentFence](ftl::SharedFuture<FenceResult> futureFenceResult) {
+ EXPECT_EQ(FenceResult(presentFence), futureFenceResult.get());
});
EXPECT_CALL(*releasedLayer3, onLayerDisplayed(_))
- .WillOnce([&layerFD](std::shared_future<renderengine::RenderEngineResult>
- futureRenderEngineResult) {
- EXPECT_EQ(layerFD, futureRenderEngineResult.get().drawFence);
+ .WillOnce([&presentFence](ftl::SharedFuture<FenceResult> futureFenceResult) {
+ EXPECT_EQ(FenceResult(presentFence), futureFenceResult.get());
});
mOutput.postFramebuffer();
@@ -4798,10 +4813,14 @@
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,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer2.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
layer2.layerFEState.backgroundBlurRadius = 10;
layer2.layerFEState.isOpaque = true;
@@ -4830,14 +4849,20 @@
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,
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,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer3.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
layer2.layerFEState.backgroundBlurRadius = 10;
layer2.layerFEState.isOpaque = false;
@@ -4867,14 +4892,20 @@
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,
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,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer3.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
BlurRegion region;
layer2.layerFEState.blurRegions.push_back(region);
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
index 96c28c9..50e3a28 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
@@ -1340,14 +1340,14 @@
EXPECT_NE(nullptr, overrideBuffer4);
}
-TEST_F(FlattenerTest, flattenLayers_skips_DISPLAY_DECORATION) {
+TEST_F(FlattenerTest, flattenLayers_includes_DISPLAY_DECORATION) {
auto& layerState1 = mTestLayers[0]->layerState;
const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer;
auto& layerState2 = mTestLayers[1]->layerState;
const auto& overrideBuffer2 = layerState2->getOutputLayer()->getState().overrideInfo.buffer;
- // The third layer uses DISPLAY_DECORATION, which should never be cached.
+ // The third layer uses DISPLAY_DECORATION, which should be cached.
auto& layerState3 = mTestLayers[2]->layerState;
const auto& overrideBuffer3 = layerState3->getOutputLayer()->getState().overrideInfo.buffer;
mTestLayers[2]->layerFECompositionState.compositionType =
@@ -1388,7 +1388,7 @@
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
- EXPECT_EQ(nullptr, overrideBuffer3);
+ EXPECT_EQ(overrideBuffer1, overrideBuffer3);
}
} // namespace
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index adf4be3..c52e96d 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -27,7 +27,6 @@
#include "HWC2.h"
#include <android/configuration.h>
-#include <ftl/future.h>
#include <ui/Fence.h>
#include <ui/FloatRect.h>
#include <ui/GraphicBuffer.h>
@@ -543,7 +542,7 @@
return error;
}
-std::future<Error> Display::setDisplayBrightness(
+ftl::Future<Error> Display::setDisplayBrightness(
float brightness, float brightnessNits,
const Hwc2::Composer::DisplayBrightnessOptions& options) {
return ftl::defer([composer = &mComposer, id = mId, brightness, brightnessNits, options] {
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index cca20bd..24aef9b 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -18,6 +18,7 @@
#include <android-base/expected.h>
#include <android-base/thread_annotations.h>
+#include <ftl/future.h>
#include <gui/HdrMetadata.h>
#include <math/mat4.h>
#include <ui/HdrCapabilities.h>
@@ -28,7 +29,6 @@
#include <utils/Timers.h>
#include <functional>
-#include <future>
#include <string>
#include <unordered_map>
#include <unordered_set>
@@ -147,7 +147,7 @@
uint32_t* outNumRequests,
android::sp<android::Fence>* outPresentFence,
uint32_t* state) = 0;
- [[nodiscard]] virtual std::future<hal::Error> setDisplayBrightness(
+ [[nodiscard]] virtual ftl::Future<hal::Error> setDisplayBrightness(
float brightness, float brightnessNits,
const Hwc2::Composer::DisplayBrightnessOptions& options) = 0;
[[nodiscard]] virtual hal::Error setActiveConfigWithConstraints(
@@ -229,7 +229,7 @@
uint32_t* outNumRequests,
android::sp<android::Fence>* outPresentFence,
uint32_t* state) override;
- std::future<hal::Error> setDisplayBrightness(
+ ftl::Future<hal::Error> setDisplayBrightness(
float brightness, float brightnessNits,
const Hwc2::Composer::DisplayBrightnessOptions& options) override;
hal::Error setActiveConfigWithConstraints(hal::HWConfigId configId,
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 79e4c75..0da8ece 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -30,7 +30,6 @@
#include <compositionengine/Output.h>
#include <compositionengine/OutputLayer.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
-#include <ftl/future.h>
#include <log/log.h>
#include <ui/DebugUtils.h>
#include <ui/GraphicBuffer.h>
@@ -720,13 +719,13 @@
return NO_ERROR;
}
-std::future<status_t> HWComposer::setDisplayBrightness(
+ftl::Future<status_t> HWComposer::setDisplayBrightness(
PhysicalDisplayId displayId, float brightness, float brightnessNits,
const Hwc2::Composer::DisplayBrightnessOptions& options) {
RETURN_IF_INVALID_DISPLAY(displayId, ftl::yield<status_t>(BAD_INDEX));
auto& display = mDisplayData[displayId].hwcDisplay;
- return ftl::chain(display->setDisplayBrightness(brightness, brightnessNits, options))
+ return display->setDisplayBrightness(brightness, brightnessNits, options)
.then([displayId](hal::Error error) -> status_t {
if (error == hal::Error::UNSUPPORTED) {
RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 7dc10ea..4c0ecd8 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -17,7 +17,6 @@
#pragma once
#include <cstdint>
-#include <future>
#include <memory>
#include <mutex>
#include <optional>
@@ -26,6 +25,7 @@
#include <vector>
#include <android-base/thread_annotations.h>
+#include <ftl/future.h>
#include <ui/DisplayIdentification.h>
#include <ui/FenceTime.h>
@@ -195,7 +195,7 @@
DisplayedFrameStats* outStats) = 0;
// Sets the brightness of a display.
- virtual std::future<status_t> setDisplayBrightness(
+ virtual ftl::Future<status_t> setDisplayBrightness(
PhysicalDisplayId, float brightness, float brightnessNits,
const Hwc2::Composer::DisplayBrightnessOptions&) = 0;
@@ -372,7 +372,7 @@
uint64_t maxFrames) override;
status_t getDisplayedContentSample(HalDisplayId, uint64_t maxFrames, uint64_t timestamp,
DisplayedFrameStats* outStats) override;
- std::future<status_t> setDisplayBrightness(
+ ftl::Future<status_t> setDisplayBrightness(
PhysicalDisplayId, float brightness, float brightnessNits,
const Hwc2::Composer::DisplayBrightnessOptions&) override;
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 659efd8..b5678b4 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -64,9 +64,10 @@
PowerAdvisor::~PowerAdvisor() = default;
namespace {
-int32_t getUpdateTimeout() {
+std::chrono::milliseconds getUpdateTimeout() {
// Default to a timeout of 80ms if nothing else is specified
- static int32_t timeout = sysprop::display_update_imminent_timeout_ms(80);
+ static std::chrono::milliseconds timeout =
+ std::chrono::milliseconds(sysprop::display_update_imminent_timeout_ms(80));
return timeout;
}
@@ -80,22 +81,35 @@
} // namespace
-PowerAdvisor::PowerAdvisor(SurfaceFlinger& flinger)
- : mFlinger(flinger),
- mUseScreenUpdateTimer(getUpdateTimeout() > 0),
- mScreenUpdateTimer(
- "UpdateImminentTimer", OneShotTimer::Interval(getUpdateTimeout()),
- /* resetCallback */ [this] { mSendUpdateImminent.store(false); },
- /* timeoutCallback */
- [this] {
- mSendUpdateImminent.store(true);
- mFlinger.disableExpensiveRendering();
- }) {}
+PowerAdvisor::PowerAdvisor(SurfaceFlinger& flinger) : mFlinger(flinger) {
+ if (getUpdateTimeout() > 0ms) {
+ mScreenUpdateTimer.emplace("UpdateImminentTimer", getUpdateTimeout(),
+ /* resetCallback */ nullptr,
+ /* timeoutCallback */
+ [this] {
+ while (true) {
+ auto timeSinceLastUpdate = std::chrono::nanoseconds(
+ systemTime() - mLastScreenUpdatedTime.load());
+ if (timeSinceLastUpdate >= getUpdateTimeout()) {
+ break;
+ }
+ // We may try to disable expensive rendering and allow
+ // for sending DISPLAY_UPDATE_IMMINENT hints too early if
+ // we idled very shortly after updating the screen, so
+ // make sure we wait enough time.
+ std::this_thread::sleep_for(getUpdateTimeout() -
+ timeSinceLastUpdate);
+ }
+ mSendUpdateImminent.store(true);
+ mFlinger.disableExpensiveRendering();
+ });
+ }
+}
void PowerAdvisor::init() {
// Defer starting the screen update timer until SurfaceFlinger finishes construction.
- if (mUseScreenUpdateTimer) {
- mScreenUpdateTimer.start();
+ if (mScreenUpdateTimer) {
+ mScreenUpdateTimer->start();
}
}
@@ -135,7 +149,7 @@
return;
}
- if (mSendUpdateImminent.load()) {
+ if (mSendUpdateImminent.exchange(false)) {
std::lock_guard lock(mPowerHalMutex);
HalWrapper* const halWrapper = getPowerHal();
if (halWrapper == nullptr) {
@@ -147,10 +161,18 @@
mReconnectPowerHal = true;
return;
}
+
+ if (mScreenUpdateTimer) {
+ mScreenUpdateTimer->reset();
+ } else {
+ // If we don't have a screen update timer, then we don't throttle power hal calls so
+ // flip this bit back to allow for calling into power hal again.
+ mSendUpdateImminent.store(true);
+ }
}
- if (mUseScreenUpdateTimer) {
- mScreenUpdateTimer.reset();
+ if (mScreenUpdateTimer) {
+ mLastScreenUpdatedTime.store(systemTime());
}
}
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
index 61bb32b..7c10e19 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -114,9 +114,9 @@
bool mNotifiedExpensiveRendering = false;
SurfaceFlinger& mFlinger;
- const bool mUseScreenUpdateTimer;
std::atomic_bool mSendUpdateImminent = true;
- scheduler::OneShotTimer mScreenUpdateTimer;
+ std::atomic<nsecs_t> mLastScreenUpdatedTime = 0;
+ std::optional<scheduler::OneShotTimer> mScreenUpdateTimer;
};
class AidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index e1eec8b..6ed4a94 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -151,10 +151,8 @@
mDrawingState.color.g = -1.0_hf;
mDrawingState.color.b = -1.0_hf;
}
-
CompositorTiming compositorTiming;
args.flinger->getCompositorTiming(&compositorTiming);
- mFrameEventHistory.initializeCompositorTiming(compositorTiming);
mFrameTracker.setDisplayRefreshPeriod(compositorTiming.interval);
mCallingPid = args.callingPid;
@@ -213,8 +211,7 @@
* Layer. So, the implementation is done in BufferLayer. When called on a
* EffectLayer object, it's essentially a NOP.
*/
-void Layer::onLayerDisplayed(
- std::shared_future<renderengine::RenderEngineResult> /*futureRenderEngineResult*/) {}
+void Layer::onLayerDisplayed(ftl::SharedFuture<FenceResult>) {}
void Layer::removeRelativeZ(const std::vector<Layer*>& layersInTree) {
if (mDrawingState.zOrderRelativeOf == nullptr) {
@@ -1532,53 +1529,17 @@
mFrameTracker.getStats(outStats);
}
-void Layer::dumpFrameEvents(std::string& result) {
- StringAppendF(&result, "- Layer %s (%s, %p)\n", getName().c_str(), getType(), this);
- Mutex::Autolock lock(mFrameEventHistoryMutex);
- mFrameEventHistory.checkFencesForCompletion();
- mFrameEventHistory.dump(result);
-}
-
void Layer::dumpCallingUidPid(std::string& result) const {
StringAppendF(&result, "Layer %s (%s) callingPid:%d callingUid:%d ownerUid:%d\n",
getName().c_str(), getType(), mCallingPid, mCallingUid, mOwnerUid);
}
void Layer::onDisconnect() {
- Mutex::Autolock lock(mFrameEventHistoryMutex);
- mFrameEventHistory.onDisconnect();
const int32_t layerId = getSequence();
mFlinger->mTimeStats->onDestroy(layerId);
mFlinger->mFrameTracer->onDestroy(layerId);
}
-void Layer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
- FrameEventHistoryDelta* outDelta) {
- if (newTimestamps) {
- mFlinger->mTimeStats->setPostTime(getSequence(), newTimestamps->frameNumber,
- getName().c_str(), mOwnerUid, newTimestamps->postedTime,
- getGameMode());
- mFlinger->mTimeStats->setAcquireFence(getSequence(), newTimestamps->frameNumber,
- newTimestamps->acquireFence);
- }
-
- Mutex::Autolock lock(mFrameEventHistoryMutex);
- if (newTimestamps) {
- // If there are any unsignaled fences in the aquire timeline at this
- // point, the previously queued frame hasn't been latched yet. Go ahead
- // and try to get the signal time here so the syscall is taken out of
- // the main thread's critical path.
- mAcquireTimeline.updateSignalTimes();
- // Push the new fence after updating since it's likely still pending.
- mAcquireTimeline.push(newTimestamps->acquireFence);
- mFrameEventHistory.addQueue(*newTimestamps);
- }
-
- if (outDelta) {
- mFrameEventHistory.getAndResetDelta(outDelta);
- }
-}
-
size_t Layer::getChildrenCount() const {
size_t count = 0;
for (const sp<Layer>& child : mCurrentChildren) {
@@ -2430,6 +2391,7 @@
// If the layer is a clone, we need to crop the input region to cloned root to prevent
// touches from going outside the cloned area.
if (isClone()) {
+ info.isClone = true;
if (const sp<Layer> clonedRoot = getClonedRoot()) {
const Rect rect = displayTransform.transform(Rect{clonedRoot->mScreenBounds});
info.touchableRegion = info.touchableRegion.intersect(rect);
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index ecea744..3988e51 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -432,10 +432,6 @@
virtual bool setSidebandStream(const sp<NativeHandle>& /*sidebandStream*/) { return false; };
virtual bool setTransactionCompletedListeners(
const std::vector<sp<CallbackHandle>>& /*handles*/);
- virtual bool addFrameEvent(const sp<Fence>& /*acquireFence*/, nsecs_t /*postedTime*/,
- nsecs_t /*requestedPresentTime*/) {
- return false;
- }
virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace);
virtual bool setColorSpaceAgnostic(const bool agnostic);
virtual bool setDimmingEnabled(const bool dimmingEnabled);
@@ -620,8 +616,7 @@
void prepareCompositionState(compositionengine::LayerFE::StateSubset subset) override;
std::vector<compositionengine::LayerFE::LayerSettings> prepareClientCompositionList(
compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
- void onLayerDisplayed(
- std::shared_future<renderengine::RenderEngineResult> futureRenderEngineResult) override;
+ void onLayerDisplayed(ftl::SharedFuture<FenceResult>) override;
void setWasClientComposed(const sp<Fence>& fence) override {
mLastClientCompositionFence = fence;
@@ -743,14 +738,11 @@
void miniDump(std::string& result, const DisplayDevice&) const;
void dumpFrameStats(std::string& result) const;
- void dumpFrameEvents(std::string& result);
void dumpCallingUidPid(std::string& result) const;
void clearFrameStats();
void logFrameStats();
void getFrameStats(FrameStats* outStats) const;
void onDisconnect();
- void addAndGetFrameTimestamps(const NewFrameEventsEntry* newEntry,
- FrameEventHistoryDelta* outDelta);
ui::Transform getTransform() const;
bool isTransformValid() const;
@@ -995,13 +987,6 @@
// Timestamp history for UIAutomation. Thread safe.
FrameTracker mFrameTracker;
- // Timestamp history for the consumer to query.
- // Accessed by both consumer and producer on main and binder threads.
- Mutex mFrameEventHistoryMutex;
- ConsumerFrameEventHistory mFrameEventHistory;
- FenceTimeline mAcquireTimeline;
- FenceTimeline mReleaseTimeline;
-
// main thread
sp<NativeHandle> mSidebandStream;
// False if the buffer and its contents have been previously used for GPU
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index e29e6ab..2487dbd 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -355,12 +355,15 @@
WRITEABLE);
}
- auto captureScreenResultFuture =
- mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer,
- true /* regionSampling */, false /* grayscale */, nullptr);
- auto& captureScreenResult = captureScreenResultFuture.get();
- if (captureScreenResult.drawFence.ok()) {
- sync_wait(captureScreenResult.drawFence.get(), -1);
+ constexpr bool kRegionSampling = true;
+ constexpr bool kGrayscale = false;
+
+ if (const auto fenceResult =
+ mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer,
+ kRegionSampling, kGrayscale, nullptr)
+ .get();
+ fenceResult.ok()) {
+ fenceResult.value()->waitForever(LOG_TAG);
}
std::vector<Descriptor> activeDescriptors;
diff --git a/services/surfaceflinger/Scheduler/OneShotTimer.cpp b/services/surfaceflinger/Scheduler/OneShotTimer.cpp
index 16f041a..9c6e56d 100644
--- a/services/surfaceflinger/Scheduler/OneShotTimer.cpp
+++ b/services/surfaceflinger/Scheduler/OneShotTimer.cpp
@@ -47,6 +47,7 @@
mInterval(interval),
mResetCallback(resetCallback),
mTimeoutCallback(timeoutCallback) {
+ mLastResetTime = std::chrono::steady_clock::time_point::min();
LOG_ALWAYS_FATAL_IF(!mClock, "Clock must not be provided");
}
@@ -116,9 +117,10 @@
auto triggerTime = mClock->now() + mInterval;
state = TimerState::WAITING;
- while (state == TimerState::WAITING) {
+ while (true) {
+ mWaiting = true;
constexpr auto zero = std::chrono::steady_clock::duration::zero();
- // Wait for mInterval time for semaphore signal.
+ // Wait for mInterval time to check if we need to reset or drop into the idle state.
struct timespec ts;
calculateTimeoutTime(std::chrono::nanoseconds(mInterval), &ts);
int result = sem_clockwait(&mSemaphore, CLOCK_MONOTONIC, &ts);
@@ -128,13 +130,21 @@
LOG_ALWAYS_FATAL("%s", ss.str().c_str());
}
+ mWaiting = false;
state = checkForResetAndStop(state);
- if (state == TimerState::RESET) {
- triggerTime = mClock->now() + mInterval;
- state = TimerState::WAITING;
- } else if (state == TimerState::WAITING && (triggerTime - mClock->now()) <= zero) {
+ if (state == TimerState::STOPPED) {
+ break;
+ }
+
+ if (state == TimerState::WAITING && (triggerTime - mClock->now()) <= zero) {
triggerTimeout = true;
state = TimerState::IDLE;
+ break;
+ }
+
+ if (state == TimerState::RESET) {
+ triggerTime = mLastResetTime.load() + mInterval;
+ state = TimerState::WAITING;
}
}
@@ -158,9 +168,14 @@
}
void OneShotTimer::reset() {
+ mLastResetTime = mClock->now();
mResetTriggered = true;
- int result = sem_post(&mSemaphore);
- LOG_ALWAYS_FATAL_IF(result, "sem_post failed");
+ // If mWaiting is true, then we are guaranteed to be in a block where we are waiting on
+ // mSemaphore for a timeout, rather than idling. So we can avoid a sem_post call since we can
+ // just check that we triggered a reset on timeout.
+ if (!mWaiting) {
+ LOG_ALWAYS_FATAL_IF(sem_post(&mSemaphore), "sem_post failed");
+ }
}
std::string OneShotTimer::dump() const {
diff --git a/services/surfaceflinger/Scheduler/OneShotTimer.h b/services/surfaceflinger/Scheduler/OneShotTimer.h
index 09265bb..2017c31 100644
--- a/services/surfaceflinger/Scheduler/OneShotTimer.h
+++ b/services/surfaceflinger/Scheduler/OneShotTimer.h
@@ -103,6 +103,8 @@
// check in the main loop if they were.
std::atomic<bool> mResetTriggered = false;
std::atomic<bool> mStopTriggered = false;
+ std::atomic<bool> mWaiting = false;
+ std::atomic<std::chrono::steady_clock::time_point> mLastResetTime;
};
} // namespace scheduler
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 3aa0a5f..37f0fec 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -167,18 +167,19 @@
impl::EventThread::GetVsyncPeriodFunction Scheduler::makeGetVsyncPeriodFunction() const {
return [this](uid_t uid) {
const Fps refreshRate = holdRefreshRateConfigs()->getActiveMode()->getFps();
- const nsecs_t basePeriod = refreshRate.getPeriodNsecs();
+ const auto currentPeriod =
+ mVsyncSchedule->getTracker().currentPeriod() ?: refreshRate.getPeriodNsecs();
const auto frameRate = getFrameRateOverride(uid);
if (!frameRate.has_value()) {
- return basePeriod;
+ return currentPeriod;
}
const auto divisor = RefreshRateConfigs::getFrameRateDivisor(refreshRate, *frameRate);
if (divisor <= 1) {
- return basePeriod;
+ return currentPeriod;
}
- return basePeriod * divisor;
+ return currentPeriod * divisor;
};
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e6b64c1..97d8aef 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1693,7 +1693,7 @@
}
const char* const whence = __func__;
- return ftl::chain(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
+ return ftl::Future(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
if (const auto display = getDisplayDeviceLocked(displayToken)) {
const bool supportsDisplayBrightnessCommand =
getHwComposer().getComposer()->isSupported(
@@ -1731,7 +1731,7 @@
return ftl::yield<status_t>(NAME_NOT_FOUND);
}
}))
- .then([](std::future<status_t> task) { return task; })
+ .then([](ftl::Future<status_t> task) { return task; })
.get();
}
@@ -2415,27 +2415,22 @@
const auto* display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()).get();
- getBE().mGlCompositionDoneTimeline.updateSignalTimes();
std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
if (display && display->getCompositionDisplay()->getState().usesClientComposition) {
glCompositionDoneFenceTime =
std::make_shared<FenceTime>(display->getCompositionDisplay()
->getRenderSurface()
->getClientTargetAcquireFence());
- getBE().mGlCompositionDoneTimeline.push(glCompositionDoneFenceTime);
} else {
glCompositionDoneFenceTime = FenceTime::NO_FENCE;
}
- getBE().mDisplayTimeline.updateSignalTimes();
mPreviousPresentFences[1] = mPreviousPresentFences[0];
mPreviousPresentFences[0].fence =
display ? getHwComposer().getPresentFence(display->getPhysicalId()) : Fence::NO_FENCE;
mPreviousPresentFences[0].fenceTime =
std::make_shared<FenceTime>(mPreviousPresentFences[0].fence);
- getBE().mDisplayTimeline.push(mPreviousPresentFences[0].fenceTime);
-
nsecs_t now = systemTime();
// Set presentation information before calling Layer::releasePendingBuffer, such that jank
@@ -3231,12 +3226,12 @@
if (!updateWindowInfo && mInputWindowCommands.empty()) {
return;
}
- BackgroundExecutor::getInstance().execute([updateWindowInfo,
- windowInfos = std::move(windowInfos),
- displayInfos = std::move(displayInfos),
- inputWindowCommands =
- std::move(mInputWindowCommands),
- inputFlinger = mInputFlinger, this]() {
+ BackgroundExecutor::getInstance().sendCallbacks({[updateWindowInfo,
+ windowInfos = std::move(windowInfos),
+ displayInfos = std::move(displayInfos),
+ inputWindowCommands =
+ std::move(mInputWindowCommands),
+ inputFlinger = mInputFlinger, this]() {
ATRACE_NAME("BackgroundExecutor::updateInputFlinger");
if (updateWindowInfo) {
mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos,
@@ -3249,7 +3244,7 @@
for (const auto& focusRequest : inputWindowCommands.focusRequests) {
inputFlinger->setFocusedWindow(focusRequest);
}
- });
+ }});
mInputWindowCommands.clear();
}
@@ -4974,7 +4969,6 @@
{"--displays"s, dumper(&SurfaceFlinger::dumpDisplays)},
{"--dispsync"s, dumper([this](std::string& s) { mScheduler->dumpVsync(s); })},
{"--edid"s, argsDumper(&SurfaceFlinger::dumpRawDisplayIdentificationData)},
- {"--frame-events"s, dumper(&SurfaceFlinger::dumpFrameEventsLocked)},
{"--latency"s, argsDumper(&SurfaceFlinger::dumpStatsLocked)},
{"--latency-clear"s, argsDumper(&SurfaceFlinger::clearStatsLocked)},
{"--list"s, dumper(&SurfaceFlinger::listLayersLocked)},
@@ -5141,13 +5135,6 @@
bucketTimeSec, percent);
}
-void SurfaceFlinger::dumpFrameEventsLocked(std::string& result) {
- result.append("Layer frame timestamps:\n");
- // Traverse all layers to dump frame-events for each layer
- mCurrentState.traverseInZOrder(
- [&] (Layer* layer) { layer->dumpFrameEvents(result); });
-}
-
void SurfaceFlinger::dumpCompositionDisplays(std::string& result) const {
for (const auto& [token, display] : mDisplays) {
display->getCompositionDisplay()->dump(result);
@@ -6424,10 +6411,10 @@
traverseLayersInLayerStack(layerStack, args.uid, visitor);
};
- auto captureResultFuture = captureScreenCommon(std::move(renderAreaFuture), traverseLayers,
- reqSize, args.pixelFormat, args.allowProtected,
- args.grayscale, captureListener);
- return captureResultFuture.get().status;
+ auto future = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
+ args.pixelFormat, args.allowProtected, args.grayscale,
+ captureListener);
+ return fenceStatus(future.get());
}
status_t SurfaceFlinger::captureDisplay(DisplayId displayId,
@@ -6466,11 +6453,14 @@
ALOGE("capture screen must provide a capture listener callback");
return BAD_VALUE;
}
- auto captureResultFuture =
- captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size,
- ui::PixelFormat::RGBA_8888, false /* allowProtected */,
- false /* grayscale */, captureListener);
- return captureResultFuture.get().status;
+
+ constexpr bool kAllowProtected = false;
+ constexpr bool kGrayscale = false;
+
+ auto future = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size,
+ ui::PixelFormat::RGBA_8888, kAllowProtected, kGrayscale,
+ captureListener);
+ return fenceStatus(future.get());
}
status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
@@ -6582,13 +6572,13 @@
return BAD_VALUE;
}
- auto captureResultFuture = captureScreenCommon(std::move(renderAreaFuture), traverseLayers,
- reqSize, args.pixelFormat, args.allowProtected,
- args.grayscale, captureListener);
- return captureResultFuture.get().status;
+ auto future = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
+ args.pixelFormat, args.allowProtected, args.grayscale,
+ captureListener);
+ return fenceStatus(future.get());
}
-std::shared_future<renderengine::RenderEngineResult> SurfaceFlinger::captureScreenCommon(
+ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenCommon(
RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers,
ui::Size bufferSize, ui::PixelFormat reqPixelFormat, bool allowProtected, bool grayscale,
const sp<IScreenCaptureListener>& captureListener) {
@@ -6598,7 +6588,7 @@
ALOGE("Attempted to capture screen with size (%" PRId32 ", %" PRId32
") that exceeds render target size limit.",
bufferSize.getWidth(), bufferSize.getHeight());
- return ftl::yield<renderengine::RenderEngineResult>({BAD_VALUE, base::unique_fd()}).share();
+ return ftl::yield<FenceResult>(base::unexpected(BAD_VALUE)).share();
}
// Loop over all visible layers to see whether there's any protected layer. A protected layer is
@@ -6640,7 +6630,7 @@
false /* regionSampling */, grayscale, captureListener);
}
-std::shared_future<renderengine::RenderEngineResult> SurfaceFlinger::captureScreenCommon(
+ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenCommon(
RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers,
const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling,
bool grayscale, const sp<IScreenCaptureListener>& captureListener) {
@@ -6648,59 +6638,52 @@
bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission();
- auto scheduleResultFuture = mScheduler->schedule([=,
- renderAreaFuture =
- std::move(renderAreaFuture)]() mutable
- -> std::shared_future<
- renderengine::RenderEngineResult> {
+ auto future = mScheduler->schedule([=, renderAreaFuture = std::move(renderAreaFuture)]() mutable
+ -> ftl::SharedFuture<FenceResult> {
ScreenCaptureResults captureResults;
std::unique_ptr<RenderArea> renderArea = renderAreaFuture.get();
if (!renderArea) {
ALOGW("Skipping screen capture because of invalid render area.");
captureResults.result = NO_MEMORY;
captureListener->onScreenCaptureCompleted(captureResults);
- return ftl::yield<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})
- .share();
+ return ftl::yield<FenceResult>(base::unexpected(NO_ERROR)).share();
}
- std::shared_future<renderengine::RenderEngineResult> renderEngineResultFuture;
-
+ ftl::SharedFuture<FenceResult> renderFuture;
renderArea->render([&] {
- renderEngineResultFuture =
- renderScreenImpl(*renderArea, traverseLayers, buffer,
- canCaptureBlackoutContent, regionSampling, grayscale,
- captureResults);
+ renderFuture =
+ renderScreenImpl(*renderArea, traverseLayers, buffer, canCaptureBlackoutContent,
+ regionSampling, grayscale, captureResults);
});
- // spring up a thread to unblock SF main thread and wait for
- // RenderEngineResult to be available
- if (captureListener != nullptr) {
+
+ if (captureListener) {
+ // TODO: The future returned by std::async blocks the main thread. Return a chain of
+ // futures to the Binder thread instead.
std::async([=]() mutable {
ATRACE_NAME("captureListener is nonnull!");
- auto& [status, drawFence] = renderEngineResultFuture.get();
- captureResults.result = status;
- captureResults.fence = new Fence(dup(drawFence));
+ auto fenceResult = renderFuture.get();
+ // TODO(b/232535621): Change ScreenCaptureResults to store a FenceResult.
+ captureResults.result = fenceStatus(fenceResult);
+ captureResults.fence = std::move(fenceResult).value_or(Fence::NO_FENCE);
captureListener->onScreenCaptureCompleted(captureResults);
});
}
- return renderEngineResultFuture;
+ return renderFuture;
});
- // flatten scheduleResultFuture object to single shared_future object
- if (captureListener == nullptr) {
- std::future<renderengine::RenderEngineResult> captureScreenResultFuture =
- ftl::chain(std::move(scheduleResultFuture))
- .then([=](std::shared_future<renderengine::RenderEngineResult> futureObject)
- -> renderengine::RenderEngineResult {
- auto& [status, drawFence] = futureObject.get();
- return {status, base::unique_fd(dup(drawFence))};
- });
- return captureScreenResultFuture.share();
- } else {
- return ftl::yield<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}).share();
+ if (captureListener) {
+ return ftl::yield<FenceResult>(base::unexpected(NO_ERROR)).share();
}
+
+ // Flatten nested futures.
+ auto chain = ftl::Future(std::move(future)).then([](ftl::SharedFuture<FenceResult> future) {
+ return future;
+ });
+
+ return chain.share();
}
-std::shared_future<renderengine::RenderEngineResult> SurfaceFlinger::renderScreenImpl(
+ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl(
const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
const std::shared_ptr<renderengine::ExternalTexture>& buffer,
bool canCaptureBlackoutContent, bool regionSampling, bool grayscale,
@@ -6719,8 +6702,7 @@
// the impetus on WindowManager to not persist them.
if (captureResults.capturedSecureLayers && !canCaptureBlackoutContent) {
ALOGW("FB is protected: PERMISSION_DENIED");
- return ftl::yield<renderengine::RenderEngineResult>({PERMISSION_DENIED, base::unique_fd()})
- .share();
+ return ftl::yield<FenceResult>(base::unexpected(PERMISSION_DENIED)).share();
}
captureResults.buffer = buffer->getBuffer();
@@ -6841,23 +6823,22 @@
base::unique_fd bufferFence;
getRenderEngine().useProtectedContext(useProtected);
- const constexpr bool kUseFramebufferCache = false;
- std::future<renderengine::RenderEngineResult> drawLayersResult =
- getRenderEngine().drawLayers(clientCompositionDisplay, clientRenderEngineLayers, buffer,
- kUseFramebufferCache, std::move(bufferFence));
+ constexpr bool kUseFramebufferCache = false;
+ auto chain =
+ ftl::Future(getRenderEngine().drawLayers(clientCompositionDisplay,
+ clientRenderEngineLayers, buffer,
+ kUseFramebufferCache, std::move(bufferFence)))
+ .then(&toFenceResult);
- std::shared_future<renderengine::RenderEngineResult> drawLayersResultFuture =
- drawLayersResult.share(); // drawLayersResult will be moved to shared one
-
+ const auto future = chain.share();
for (auto* layer : renderedLayers) {
- // make a copy of shared_future object for each layer
- layer->onLayerDisplayed(drawLayersResultFuture);
+ layer->onLayerDisplayed(future);
}
// Always switch back to unprotected context.
getRenderEngine().useProtectedContext(false);
- return drawLayersResultFuture;
+ return future;
}
void SurfaceFlinger::windowInfosReported() {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index fc27b62..f14c755 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -27,6 +27,7 @@
#include <android/gui/DisplayState.h>
#include <cutils/atomic.h>
#include <cutils/compiler.h>
+#include <ftl/future.h>
#include <ftl/small_map.h>
#include <gui/BufferQueue.h>
#include <gui/FrameTimestamps.h>
@@ -49,6 +50,7 @@
#include <utils/Trace.h>
#include <utils/threads.h>
+#include <compositionengine/FenceResult.h>
#include <compositionengine/OutputColorSetting.h>
#include <scheduler/Fps.h>
@@ -76,7 +78,6 @@
#include <atomic>
#include <cstdint>
#include <functional>
-#include <future>
#include <map>
#include <memory>
#include <mutex>
@@ -166,9 +167,6 @@
using DisplayColorSetting = compositionengine::OutputColorSetting;
struct SurfaceFlingerBE {
- FenceTimeline mGlCompositionDoneTimeline;
- FenceTimeline mDisplayTimeline;
-
// protected by mCompositorTimingLock;
mutable std::mutex mCompositorTimingLock;
CompositorTiming mCompositorTiming;
@@ -397,7 +395,7 @@
using VsyncModulator = scheduler::VsyncModulator;
using TransactionSchedule = scheduler::TransactionSchedule;
using TraverseLayersFunction = std::function<void(const LayerVector::Visitor&)>;
- using RenderAreaFuture = std::future<std::unique_ptr<RenderArea>>;
+ using RenderAreaFuture = ftl::Future<std::unique_ptr<RenderArea>>;
using DumpArgs = Vector<String16>;
using Dumper = std::function<void(const DumpArgs&, bool asProto, std::string&)>;
@@ -867,14 +865,15 @@
// Boot animation, on/off animations and screen capture
void startBootAnim();
- std::shared_future<renderengine::RenderEngineResult> captureScreenCommon(
- RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize, ui::PixelFormat,
- bool allowProtected, bool grayscale, const sp<IScreenCaptureListener>&);
- std::shared_future<renderengine::RenderEngineResult> captureScreenCommon(
+ ftl::SharedFuture<FenceResult> captureScreenCommon(RenderAreaFuture, TraverseLayersFunction,
+ ui::Size bufferSize, ui::PixelFormat,
+ bool allowProtected, bool grayscale,
+ const sp<IScreenCaptureListener>&);
+ ftl::SharedFuture<FenceResult> captureScreenCommon(
RenderAreaFuture, TraverseLayersFunction,
const std::shared_ptr<renderengine::ExternalTexture>&, bool regionSampling,
bool grayscale, const sp<IScreenCaptureListener>&);
- std::shared_future<renderengine::RenderEngineResult> renderScreenImpl(
+ ftl::SharedFuture<FenceResult> renderScreenImpl(
const RenderArea&, TraverseLayersFunction,
const std::shared_ptr<renderengine::ExternalTexture>&, bool canCaptureBlackoutContent,
bool regionSampling, bool grayscale, ScreenCaptureResults&) EXCLUDES(mStateLock);
@@ -1098,8 +1097,6 @@
void dumpVSync(std::string& result) const REQUIRES(mStateLock);
void dumpStaticScreenStats(std::string& result) const;
- // Not const because each Layer needs to query Fences and cache timestamps.
- void dumpFrameEventsLocked(std::string& result);
void dumpCompositionDisplays(std::string& result) const REQUIRES(mStateLock);
void dumpDisplays(std::string& result) const REQUIRES(mStateLock);
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp
index e1f348f..d2c2e29 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.cpp
+++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp
@@ -133,10 +133,10 @@
if (surfaceControl) {
sp<Fence> prevFence = nullptr;
- for (const auto& futureStruct : handle->previousReleaseFences) {
- sp<Fence> currentFence = sp<Fence>::make(dup(futureStruct.get().drawFence));
+ for (const auto& future : handle->previousReleaseFences) {
+ sp<Fence> currentFence = future.get().value_or(Fence::NO_FENCE);
if (prevFence == nullptr && currentFence->getStatus() != Fence::Status::Invalid) {
- prevFence = currentFence;
+ prevFence = std::move(currentFence);
handle->previousReleaseFence = prevFence;
} else if (prevFence != nullptr) {
// If both fences are signaled or both are unsignaled, we need to merge
@@ -147,7 +147,7 @@
snprintf(fenceName, 32, "%.28s", handle->name.c_str());
sp<Fence> mergedFence = Fence::merge(fenceName, prevFence, currentFence);
if (mergedFence->isValid()) {
- handle->previousReleaseFence = mergedFence;
+ handle->previousReleaseFence = std::move(mergedFence);
prevFence = handle->previousReleaseFence;
}
} else if (currentFence->getStatus() == Fence::Status::Unsignaled) {
@@ -158,11 +158,12 @@
// by this point, they will have both signaled and only the timestamp
// will be slightly off; any dependencies after this point will
// already have been met.
- handle->previousReleaseFence = currentFence;
+ handle->previousReleaseFence = std::move(currentFence);
}
}
}
- handle->previousReleaseFences = {};
+ handle->previousReleaseFences.clear();
+
FrameEventHistoryStats eventStats(handle->frameNumber,
handle->gpuCompositionDoneFence->getSnapshot().fence,
handle->compositorTiming, handle->refreshStartTime,
@@ -184,6 +185,7 @@
void TransactionCallbackInvoker::sendCallbacks(bool onCommitOnly) {
// For each listener
auto completedTransactionsItr = mCompletedTransactions.begin();
+ BackgroundExecutor::Callbacks callbacks;
while (completedTransactionsItr != mCompletedTransactions.end()) {
auto& [listener, transactionStatsDeque] = *completedTransactionsItr;
ListenerStats listenerStats;
@@ -218,7 +220,7 @@
// keep it as an IBinder due to consistency reasons: if we
// interface_cast at the IPC boundary when reading a Parcel,
// we get pointers that compare unequal in the SF process.
- BackgroundExecutor::getInstance().execute([stats = std::move(listenerStats)]() {
+ callbacks.emplace_back([stats = std::move(listenerStats)]() {
interface_cast<ITransactionCompletedListener>(stats.listener)
->onTransactionCompleted(stats);
});
@@ -230,6 +232,8 @@
if (mPresentFence) {
mPresentFence.clear();
}
+
+ BackgroundExecutor::getInstance().sendCallbacks(std::move(callbacks));
}
// -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h
index a68cd87..81d79f0 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.h
+++ b/services/surfaceflinger/TransactionCallbackInvoker.h
@@ -18,7 +18,6 @@
#include <condition_variable>
#include <deque>
-#include <future>
#include <mutex>
#include <queue>
#include <thread>
@@ -26,10 +25,10 @@
#include <unordered_set>
#include <android-base/thread_annotations.h>
-
#include <binder/IBinder.h>
+#include <compositionengine/FenceResult.h>
+#include <ftl/future.h>
#include <gui/ITransactionCompletedListener.h>
-#include <renderengine/RenderEngine.h>
#include <ui/Fence.h>
namespace android {
@@ -46,7 +45,7 @@
bool releasePreviousBuffer = false;
std::string name;
sp<Fence> previousReleaseFence;
- std::vector<std::shared_future<renderengine::RenderEngineResult>> previousReleaseFences;
+ std::vector<ftl::SharedFuture<FenceResult>> previousReleaseFences;
std::variant<nsecs_t, sp<Fence>> acquireTimeOrFence = -1;
nsecs_t latchTime = -1;
uint32_t transformHint = 0;
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index a80aca2..867a198 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -456,9 +456,6 @@
mFlinger->dumpStaticScreenStats(result);
result = fdp->ConsumeRandomLengthString().c_str();
- mFlinger->dumpFrameEventsLocked(result);
-
- result = fdp->ConsumeRandomLengthString().c_str();
mFlinger->dumpRawDisplayIdentificationData(dumpArgs, result);
LayersProto layersProto = mFlinger->dumpDrawingStateProto(fdp->ConsumeIntegral<uint32_t>());
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
index 46d52dd..34cf906 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
@@ -21,6 +21,7 @@
#include <LayerRejecter.h>
#include <LayerRenderArea.h>
#include <MonitoredProducer.h>
+#include <ftl/future.h>
#include <fuzzer/FuzzedDataProvider.h>
#include <gui/IProducerListener.h>
#include <gui/LayerDebugInfo.h>
@@ -117,11 +118,11 @@
const CompositorTiming compositor = {mFdp.ConsumeIntegral<int64_t>(),
mFdp.ConsumeIntegral<int64_t>(),
mFdp.ConsumeIntegral<int64_t>()};
- std::packaged_task<renderengine::RenderEngineResult()> renderResult([&] {
- return renderengine::RenderEngineResult{mFdp.ConsumeIntegral<int32_t>(),
- base::unique_fd(fence->get())};
- });
- layer->onLayerDisplayed(renderResult.get_future());
+
+ layer->onLayerDisplayed(ftl::yield<FenceResult>(fence).share());
+ layer->onLayerDisplayed(
+ ftl::yield<FenceResult>(base::unexpected(mFdp.ConsumeIntegral<status_t>())).share());
+
layer->releasePendingBuffer(mFdp.ConsumeIntegral<int64_t>());
layer->finalizeFrameEventHistory(fenceTime, compositor);
layer->onPostComposition(nullptr, fenceTime, fenceTime, compositor);
@@ -146,8 +147,6 @@
const bool ownsHandle = mFdp.ConsumeBool();
sp<NativeHandle> nativeHandle = sp<NativeHandle>::make(testHandle, ownsHandle);
layer->setSidebandStream(nativeHandle);
- layer->addFrameEvent(fence, mFdp.ConsumeIntegral<int64_t>() /*postedTime*/,
- mFdp.ConsumeIntegral<int64_t>() /*requestedTime*/);
layer->computeSourceBounds(getFuzzedFloatRect(&mFdp));
layer->fenceHasSignaled();
diff --git a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
index 027a15e..a6d7f58 100644
--- a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
+++ b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
@@ -465,4 +465,22 @@
ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId));
}
+TEST_F(ReleaseBufferCallbackTest, SetBuffer_OverwriteBuffersWithNull) {
+ sp<SurfaceControl> layer = createBufferStateLayer();
+ ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper();
+
+ sp<GraphicBuffer> firstBuffer = getBuffer();
+ ReleaseCallbackId firstBufferCallbackId(firstBuffer->getId(), generateFrameNumber());
+
+ // Create transaction with a buffer.
+ Transaction transaction;
+ transaction.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber,
+ releaseCallback->getCallback());
+
+ // Call setBuffer on the same transaction with a null buffer.
+ transaction.setBuffer(layer, nullptr, std::nullopt, 0, releaseCallback->getCallback());
+
+ ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId));
+}
+
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index c541b92..bbfedc7 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -245,15 +245,14 @@
HAL_PIXEL_FORMAT_RGBA_8888, 1,
usage);
- auto result = mFlinger.renderScreenImpl(*renderArea, traverseLayers, mCaptureScreenBuffer,
+ auto future = mFlinger.renderScreenImpl(*renderArea, traverseLayers, mCaptureScreenBuffer,
forSystem, regionSampling);
- EXPECT_TRUE(result.valid());
+ ASSERT_TRUE(future.valid());
+ const auto fenceResult = future.get();
- auto& [status, drawFence] = result.get();
-
- EXPECT_EQ(NO_ERROR, status);
- if (drawFence.ok()) {
- sync_wait(drawFence.get(), -1);
+ EXPECT_EQ(NO_ERROR, fenceStatus(fenceResult));
+ if (fenceResult.ok()) {
+ fenceResult.value()->waitForever(LOG_TAG);
}
LayerCase::cleanup(this);
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
index 3e0d6d3..07cd15d 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
@@ -80,7 +80,7 @@
MOCK_METHOD(hal::Error, presentOrValidate,
(nsecs_t, uint32_t *, uint32_t *, android::sp<android::Fence> *, uint32_t *),
(override));
- MOCK_METHOD(std::future<hal::Error>, setDisplayBrightness,
+ MOCK_METHOD(ftl::Future<hal::Error>, setDisplayBrightness,
(float, float, const Hwc2::Composer::DisplayBrightnessOptions &), (override));
MOCK_METHOD(hal::Error, setActiveConfigWithConstraints,
(hal::HWConfigId, const hal::VsyncPeriodChangeConstraints &,