Merge "SkiaVkRenderEngine: Do not cache textures with protected contexts" into udc-dev
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index c71c4a0..39eb4ab 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -14,6 +14,7 @@
include/powermanager/
libs/binder/fuzzer/
libs/binder/
+ libs/binderdebug/
libs/binderthreadstate/
libs/graphicsenv/
libs/gui/
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 95f5c03..e66cc41 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -501,6 +501,33 @@
chmod 0440 /sys/kernel/debug/tracing/hyp/events/hyp/hyp_exit/id
chmod 0440 /sys/kernel/tracing/hyp/events/hyp/hyp_exit/id
+# host_hcall event
+ chmod 0660 /sys/kernel/debug/tracing/hyp/events/hyp/host_hcall/enable
+ chmod 0660 /sys/kernel/tracing/hyp/events/hyp/host_hcall/enable
+# TODO(b/249050813): should this be handled in kernel?
+ chmod 0440 /sys/kernel/debug/tracing/hyp/events/hyp/host_hcall/format
+ chmod 0440 /sys/kernel/tracing/hyp/events/hyp/host_hcall/format
+ chmod 0440 /sys/kernel/debug/tracing/hyp/events/hyp/host_hcall/id
+ chmod 0440 /sys/kernel/tracing/hyp/events/hyp/host_hcall/id
+
+# host_smc event
+ chmod 0660 /sys/kernel/debug/tracing/hyp/events/hyp/host_smc/enable
+ chmod 0660 /sys/kernel/tracing/hyp/events/hyp/host_smc/enable
+# TODO(b/249050813): should this be handled in kernel?
+ chmod 0440 /sys/kernel/debug/tracing/hyp/events/hyp/host_smc/format
+ chmod 0440 /sys/kernel/tracing/hyp/events/hyp/host_smc/format
+ chmod 0440 /sys/kernel/debug/tracing/hyp/events/hyp/host_smc/id
+ chmod 0440 /sys/kernel/tracing/hyp/events/hyp/host_smc/id
+
+# host_mem_abort event
+ chmod 0660 /sys/kernel/debug/tracing/hyp/events/hyp/host_mem_abort/enable
+ chmod 0660 /sys/kernel/tracing/hyp/events/hyp/host_mem_abort/enable
+# TODO(b/249050813): should this be handled in kernel?
+ chmod 0440 /sys/kernel/debug/tracing/hyp/events/hyp/host_mem_abort/format
+ chmod 0440 /sys/kernel/tracing/hyp/events/hyp/host_mem_abort/format
+ chmod 0440 /sys/kernel/debug/tracing/hyp/events/hyp/host_mem_abort/id
+ chmod 0440 /sys/kernel/tracing/hyp/events/hyp/host_mem_abort/id
+
on property:persist.debug.atrace.boottrace=1
start boottrace
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 23cdd10..6f84e7c 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1254,8 +1254,9 @@
dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
dumpsys.writeDumpFooter(STDOUT_FILENO, service, std::chrono::milliseconds(1));
} else {
- status_t status = dumpsys.startDumpThread(Dumpsys::TYPE_DUMP, service, args);
- if (status == OK) {
+ status_t status = dumpsys.startDumpThread(Dumpsys::TYPE_DUMP | Dumpsys::TYPE_PID,
+ service, args);
+ if (status == OK) {
dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
std::chrono::duration<double> elapsed_seconds;
if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH &&
@@ -1902,6 +1903,9 @@
}
ds.AddDir(PREREBOOT_DATA_DIR, false);
add_mountinfo();
+ for (const char* path : {"/proc/cpuinfo", "/proc/meminfo"}) {
+ ds.AddZipEntry(ZIP_ROOT_DIR + path, path);
+ }
DumpIpTablesAsRoot();
DumpDynamicPartitionInfo();
ds.AddDir(OTA_METADATA_DIR, true);
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 794750f..1693ed5 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -1942,7 +1942,8 @@
RUNTIME_NATIVE_BOOT_NAMESPACE,
ENABLE_JITZYGOTE_IMAGE,
/*default_value=*/ "");
- bool use_jitzygote_image = jitzygote_flag == "true" || IsBootClassPathProfilingEnable();
+ bool compile_without_image = jitzygote_flag == "true" || IsBootClassPathProfilingEnable() ||
+ force_compile_without_image();
// Decide whether to use dex2oat64.
bool use_dex2oat64 = false;
@@ -1964,7 +1965,7 @@
in_dex, in_vdex, dex_metadata, reference_profile, class_loader_context,
join_fds(context_input_fds), swap_fd.get(), instruction_set, compiler_filter,
debuggable, boot_complete, for_restore, target_sdk_version,
- enable_hidden_api_checks, generate_compact_dex, use_jitzygote_image,
+ enable_hidden_api_checks, generate_compact_dex, compile_without_image,
background_job_compile, compilation_reason);
bool cancelled = false;
diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp
index b5bc28c..4f691c9 100644
--- a/cmds/installd/installd.cpp
+++ b/cmds/installd/installd.cpp
@@ -65,6 +65,10 @@
return create_cache_path_default(path, src, instruction_set);
}
+bool force_compile_without_image() {
+ return false;
+}
+
static bool initialize_globals() {
return init_globals_from_data_and_root();
}
diff --git a/cmds/installd/installd_deps.h b/cmds/installd/installd_deps.h
index 5093178..0d0a7fa 100644
--- a/cmds/installd/installd_deps.h
+++ b/cmds/installd/installd_deps.h
@@ -57,6 +57,9 @@
const char *src,
const char *instruction_set);
+// If true, pass "--force-jit-zygote" to dex2oat (i.e., compile without a boot image).
+extern bool force_compile_without_image();
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index bf2c0d1..7cabdb0 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -711,6 +711,11 @@
return true;
}
+bool force_compile_without_image() {
+ // We don't have a boot image anyway. Compile without a boot image.
+ return true;
+}
+
static int log_callback(int type, const char *fmt, ...) {
va_list ap;
int priority;
diff --git a/cmds/installd/tests/installd_cache_test.cpp b/cmds/installd/tests/installd_cache_test.cpp
index 4976646..a00c2c7 100644
--- a/cmds/installd/tests/installd_cache_test.cpp
+++ b/cmds/installd/tests/installd_cache_test.cpp
@@ -67,6 +67,10 @@
return false;
}
+bool force_compile_without_image() {
+ return false;
+}
+
static void mkdir(const char* path) {
const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path);
::mkdir(fullPath.c_str(), 0755);
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 5c4e1a4..be4ca43 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -73,6 +73,10 @@
return create_cache_path_default(path, src, instruction_set);
}
+bool force_compile_without_image() {
+ return false;
+}
+
static void run_cmd(const std::string& cmd) {
system(cmd.c_str());
}
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index f86f1d5..858a92c 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -113,6 +113,10 @@
return create_cache_path_default(path, src, instruction_set);
}
+bool force_compile_without_image() {
+ return false;
+}
+
static std::string get_full_path(const std::string& path) {
return StringPrintf("%s/%s", kTestPath.c_str(), path.c_str());
}
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index a737bd3..bdd5172 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -167,12 +167,6 @@
}
prebuilt_etc {
- name: "android.hardware.telephony.satellite.prebuilt.xml",
- src: "android.hardware.telephony.satellite.xml",
- defaults: ["frameworks_native_data_etc_defaults"],
-}
-
-prebuilt_etc {
name: "android.hardware.usb.accessory.prebuilt.xml",
src: "android.hardware.usb.accessory.xml",
defaults: ["frameworks_native_data_etc_defaults"],
diff --git a/data/etc/android.hardware.telephony.satellite.xml b/data/etc/android.hardware.telephony.satellite.xml
deleted file mode 100644
index 5966cba..0000000
--- a/data/etc/android.hardware.telephony.satellite.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<!-- Feature for devices that support Satellite communication via Satellite HAL APIs. -->
-<permissions>
- <feature name="android.hardware.telephony.satellite" />
-</permissions>
diff --git a/include/ftl/details/optional.h b/include/ftl/details/optional.h
index bff7c1e..e45c1f5 100644
--- a/include/ftl/details/optional.h
+++ b/include/ftl/details/optional.h
@@ -54,5 +54,15 @@
template <typename F, typename T>
using and_then_result_t = typename and_then_result<F, T>::type;
+template <typename F, typename T>
+struct or_else_result {
+ using type = remove_cvref_t<std::invoke_result_t<F>>;
+ static_assert(std::is_same_v<type, std::optional<T>> || std::is_same_v<type, Optional<T>>,
+ "or_else function must return an optional T");
+};
+
+template <typename F, typename T>
+using or_else_result_t = typename or_else_result<F, T>::type;
+
} // namespace details
} // namespace android::ftl
diff --git a/include/ftl/optional.h b/include/ftl/optional.h
index a818128..94d8e3d 100644
--- a/include/ftl/optional.h
+++ b/include/ftl/optional.h
@@ -96,13 +96,25 @@
return R();
}
+ // Returns this Optional<T> if not nullopt, or else the Optional<T> returned by the function F.
+ template <typename F>
+ constexpr auto or_else(F&& f) const& -> details::or_else_result_t<F, T> {
+ if (has_value()) return *this;
+ return std::forward<F>(f)();
+ }
+
+ template <typename F>
+ constexpr auto or_else(F&& f) && -> details::or_else_result_t<F, T> {
+ if (has_value()) return std::move(*this);
+ return std::forward<F>(f)();
+ }
+
// Delete new for this class. Its base doesn't have a virtual destructor, and
// if it got deleted via base class pointer, it would cause undefined
// behavior. There's not a good reason to allocate this object on the heap
// anyway.
static void* operator new(size_t) = delete;
static void* operator new[](size_t) = delete;
-
};
template <typename T, typename U>
diff --git a/include/input/Input.h b/include/input/Input.h
index 608519b..e8af5f7 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -855,6 +855,8 @@
const PointerCoords&);
static PointerCoords calculateTransformedCoords(uint32_t source, const ui::Transform&,
const PointerCoords&);
+ // The rounding precision for transformed motion events.
+ static constexpr float ROUNDING_PRECISION = 0.001f;
protected:
int32_t mAction;
diff --git a/include/input/PropertyMap.h b/include/input/PropertyMap.h
index 18ce16d..2e44142 100644
--- a/include/input/PropertyMap.h
+++ b/include/input/PropertyMap.h
@@ -19,6 +19,7 @@
#include <android-base/result.h>
#include <utils/Tokenizer.h>
+#include <optional>
#include <string>
#include <unordered_map>
#include <unordered_set>
@@ -63,15 +64,15 @@
/* Returns a set of all property keys starting with the given prefix. */
std::unordered_set<std::string> getKeysWithPrefix(const std::string& prefix) const;
- /* Gets the value of a property and parses it.
- * Returns true and sets outValue if the key was found and its value was parsed successfully.
- * Otherwise returns false and does not modify outValue. (Also logs a warning.)
+ /* Gets the value of a property and parses it. Returns nullopt if the key wasn't found or
+ * couldn't be parsed as the requested type. (Warnings are also logged in the case of parsing
+ * failures.)
*/
- bool tryGetProperty(const std::string& key, std::string& outValue) const;
- bool tryGetProperty(const std::string& key, bool& outValue) const;
- bool tryGetProperty(const std::string& key, int32_t& outValue) const;
- bool tryGetProperty(const std::string& key, float& outValue) const;
- bool tryGetProperty(const std::string& key, double& outValue) const;
+ std::optional<std::string> getString(const std::string& key) const;
+ std::optional<bool> getBool(const std::string& key) const;
+ std::optional<int32_t> getInt(const std::string& key) const;
+ std::optional<float> getFloat(const std::string& key) const;
+ std::optional<double> getDouble(const std::string& key) const;
/* Adds all values from the specified property map. */
void addAll(const PropertyMap* map);
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 6a354b4..3f19371 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -191,6 +191,7 @@
"google-*",
"misc-*",
"performance*",
+ "-performance-move-const-arg", // b/273486801
"portability*",
],
}
diff --git a/libs/binder/RecordedTransaction.cpp b/libs/binder/RecordedTransaction.cpp
index 51b97165..ef58ed3 100644
--- a/libs/binder/RecordedTransaction.cpp
+++ b/libs/binder/RecordedTransaction.cpp
@@ -127,8 +127,7 @@
t.mData.mInterfaceName = std::string(String8(interfaceName).string());
if (interfaceName.size() != t.mData.mInterfaceName.size()) {
LOG(ERROR) << "Interface Name is not valid. Contains characters that aren't single byte "
- "utf-8: "
- << interfaceName;
+ "utf-8.";
return std::nullopt;
}
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index 38bd081..ed3ce24 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -262,8 +262,10 @@
}
void RpcState::clear() {
- RpcMutexUniqueLock _l(mNodeMutex);
+ return clear(RpcMutexUniqueLock(mNodeMutex));
+}
+void RpcState::clear(RpcMutexUniqueLock nodeLock) {
if (mTerminated) {
LOG_ALWAYS_FATAL_IF(!mNodeForAddress.empty(),
"New state should be impossible after terminating!");
@@ -292,7 +294,7 @@
auto temp = std::move(mNodeForAddress);
mNodeForAddress.clear(); // RpcState isn't reusable, but for future/explicit
- _l.unlock();
+ nodeLock.unlock();
temp.clear(); // explicit
}
@@ -704,7 +706,7 @@
};
{
- RpcMutexLockGuard _l(mNodeMutex);
+ RpcMutexUniqueLock _l(mNodeMutex);
if (mTerminated) return DEAD_OBJECT; // avoid fatal only, otherwise races
auto it = mNodeForAddress.find(addr);
LOG_ALWAYS_FATAL_IF(it == mNodeForAddress.end(),
@@ -720,8 +722,9 @@
body.amount = it->second.timesRecd - target;
it->second.timesRecd = target;
- LOG_ALWAYS_FATAL_IF(nullptr != tryEraseNode(it),
+ LOG_ALWAYS_FATAL_IF(nullptr != tryEraseNode(session, std::move(_l), it),
"Bad state. RpcState shouldn't own received binder");
+ // LOCK ALREADY RELEASED
}
RpcWireHeader cmd = {
@@ -1164,8 +1167,8 @@
it->second.timesSent);
it->second.timesSent -= body.amount;
- sp<IBinder> tempHold = tryEraseNode(it);
- _l.unlock();
+ sp<IBinder> tempHold = tryEraseNode(session, std::move(_l), it);
+ // LOCK ALREADY RELEASED
tempHold = nullptr; // destructor may make binder calls on this session
return OK;
@@ -1229,7 +1232,10 @@
return OK;
}
-sp<IBinder> RpcState::tryEraseNode(std::map<uint64_t, BinderNode>::iterator& it) {
+sp<IBinder> RpcState::tryEraseNode(const sp<RpcSession>& session, RpcMutexUniqueLock nodeLock,
+ std::map<uint64_t, BinderNode>::iterator& it) {
+ bool shouldShutdown = false;
+
sp<IBinder> ref;
if (it->second.timesSent == 0) {
@@ -1239,9 +1245,27 @@
LOG_ALWAYS_FATAL_IF(!it->second.asyncTodo.empty(),
"Can't delete binder w/ pending async transactions");
mNodeForAddress.erase(it);
+
+ if (mNodeForAddress.size() == 0) {
+ shouldShutdown = true;
+ }
}
}
+ // If we shutdown, prevent RpcState from being re-used. This prevents another
+ // thread from getting the root object again.
+ if (shouldShutdown) {
+ clear(std::move(nodeLock));
+ } else {
+ nodeLock.unlock(); // explicit
+ }
+ // LOCK IS RELEASED
+
+ if (shouldShutdown) {
+ ALOGI("RpcState has no binders left, so triggering shutdown...");
+ (void)session->shutdownAndWait(false);
+ }
+
return ref;
}
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index ac86585..0e23ea7 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -168,6 +168,7 @@
void clear();
private:
+ void clear(RpcMutexUniqueLock nodeLock);
void dumpLocked();
// Alternative to std::vector<uint8_t> that doesn't abort on allocation failure and caps
@@ -268,11 +269,20 @@
std::string toString() const;
};
- // checks if there is any reference left to a node and erases it. If erase
- // happens, and there is a strong reference to the binder kept by
- // binderNode, this returns that strong reference, so that it can be
- // dropped after any locks are removed.
- sp<IBinder> tryEraseNode(std::map<uint64_t, BinderNode>::iterator& it);
+ // Checks if there is any reference left to a node and erases it. If this
+ // is the last node, shuts down the session.
+ //
+ // Node lock is passed here for convenience, so that we can release it
+ // and terminate the session, but we could leave it up to the caller
+ // by returning a continuation if we needed to erase multiple specific
+ // nodes. It may be tempting to allow the client to keep on holding the
+ // lock and instead just return whether or not we should shutdown, but
+ // this introduces the posssibility that another thread calls
+ // getRootBinder and thinks it is valid, rather than immediately getting
+ // an error.
+ sp<IBinder> tryEraseNode(const sp<RpcSession>& session, RpcMutexUniqueLock nodeLock,
+ std::map<uint64_t, BinderNode>::iterator& it);
+
// true - success
// false - session shutdown, halt
[[nodiscard]] bool nodeProgressAsyncNumber(BinderNode* node);
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 1488400..07b38d7 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -119,5 +119,10 @@
{
"name": "memunreachable_binder_test"
}
+ ],
+ "imports": [
+ {
+ "path": "packages/modules/Virtualization"
+ }
]
}
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index 0750ccf..a323feb 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -51,6 +51,9 @@
* This represents a session (group of connections) between a client
* and a server. Multiple connections are needed for multiple parallel "binder"
* calls which may also have nested calls.
+ *
+ * Once a binder exists in the session, if all references to all binders are dropped,
+ * the session shuts down.
*/
class RpcSession final : public virtual RefBase {
public:
diff --git a/libs/binder/ndk/include_platform/android/binder_process.h b/libs/binder/ndk/include_platform/android/binder_process.h
index ffcad55..3fbe90d 100644
--- a/libs/binder/ndk/include_platform/android/binder_process.h
+++ b/libs/binder/ndk/include_platform/android/binder_process.h
@@ -32,7 +32,7 @@
* Do not use this from a library. Apps setup their own threadpools, and otherwise, the main
* function should be responsible for configuring the threadpool for the entire application.
*/
-void ABinderProcess_startThreadPool();
+void ABinderProcess_startThreadPool(void);
/**
* This sets the maximum number of threads that can be started in the threadpool. By default, after
* startThreadPool is called, this is 15. If it is called additional times, it will only prevent
@@ -48,7 +48,7 @@
* you should use this in a library to abort if the threadpool is not started.
* Programs should configure binder threadpools once at the beginning.
*/
-bool ABinderProcess_isThreadPoolStarted();
+bool ABinderProcess_isThreadPoolStarted(void);
/**
* This adds the current thread to the threadpool. This may cause the threadpool to exceed the
* maximum size.
@@ -56,7 +56,7 @@
* Do not use this from a library. Apps setup their own threadpools, and otherwise, the main
* function should be responsible for configuring the threadpool for the entire application.
*/
-void ABinderProcess_joinThreadPool();
+void ABinderProcess_joinThreadPool(void);
/**
* This gives you an fd to wait on. Whenever data is available on the fd,
@@ -79,6 +79,6 @@
*
* \return STATUS_OK on success
*/
-__attribute__((weak)) binder_status_t ABinderProcess_handlePolledCommands() __INTRODUCED_IN(31);
+__attribute__((weak)) binder_status_t ABinderProcess_handlePolledCommands(void) __INTRODUCED_IN(31);
__END_DECLS
diff --git a/libs/binder/ndk/process.cpp b/libs/binder/ndk/process.cpp
index bc6610e..0fea57b 100644
--- a/libs/binder/ndk/process.cpp
+++ b/libs/binder/ndk/process.cpp
@@ -24,17 +24,17 @@
using ::android::IPCThreadState;
using ::android::ProcessState;
-void ABinderProcess_startThreadPool() {
+void ABinderProcess_startThreadPool(void) {
ProcessState::self()->startThreadPool();
ProcessState::self()->giveThreadPoolName();
}
bool ABinderProcess_setThreadPoolMaxThreadCount(uint32_t numThreads) {
return ProcessState::self()->setThreadPoolMaxThreadCount(numThreads) == 0;
}
-bool ABinderProcess_isThreadPoolStarted() {
+bool ABinderProcess_isThreadPoolStarted(void) {
return ProcessState::self()->isThreadPoolStarted();
}
-void ABinderProcess_joinThreadPool() {
+void ABinderProcess_joinThreadPool(void) {
IPCThreadState::self()->joinThreadPool();
}
@@ -42,6 +42,6 @@
return IPCThreadState::self()->setupPolling(fd);
}
-binder_status_t ABinderProcess_handlePolledCommands() {
+binder_status_t ABinderProcess_handlePolledCommands(void) {
return IPCThreadState::self()->handlePolledCommands();
}
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 976f54d..d0e35de 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -100,22 +100,17 @@
/// An interface can promise to be a stable vendor interface ([`Vintf`]), or
/// makes no stability guarantees ([`Local`]). [`Local`] is
/// currently the default stability.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default)]
pub enum Stability {
/// Default stability, visible to other modules in the same compilation
/// context (e.g. modules on system.img)
+ #[default]
Local,
/// A Vendor Interface Object, which promises to be stable
Vintf,
}
-impl Default for Stability {
- fn default() -> Self {
- Stability::Local
- }
-}
-
impl From<Stability> for i32 {
fn from(stability: Stability) -> i32 {
use Stability::*;
diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs
index 6f4c375..4b658fc 100644
--- a/libs/binder/rust/src/parcel/parcelable.rs
+++ b/libs/binder/rust/src/parcel/parcelable.rs
@@ -771,7 +771,13 @@
#[macro_export]
macro_rules! impl_serialize_for_parcelable {
($parcelable:ident) => {
- impl $crate::binder_impl::Serialize for $parcelable {
+ $crate::impl_serialize_for_parcelable!($parcelable < >);
+ };
+ ($parcelable:ident < $( $param:ident ),* , >) => {
+ $crate::impl_serialize_for_parcelable!($parcelable < $($param),* >);
+ };
+ ($parcelable:ident < $( $param:ident ),* > ) => {
+ impl < $($param),* > $crate::binder_impl::Serialize for $parcelable < $($param),* > {
fn serialize(
&self,
parcel: &mut $crate::binder_impl::BorrowedParcel<'_>,
@@ -780,9 +786,9 @@
}
}
- impl $crate::binder_impl::SerializeArray for $parcelable {}
+ impl < $($param),* > $crate::binder_impl::SerializeArray for $parcelable < $($param),* > {}
- impl $crate::binder_impl::SerializeOption for $parcelable {
+ impl < $($param),* > $crate::binder_impl::SerializeOption for $parcelable < $($param),* > {
fn serialize_option(
this: Option<&Self>,
parcel: &mut $crate::binder_impl::BorrowedParcel<'_>,
@@ -808,7 +814,13 @@
#[macro_export]
macro_rules! impl_deserialize_for_parcelable {
($parcelable:ident) => {
- impl $crate::binder_impl::Deserialize for $parcelable {
+ $crate::impl_deserialize_for_parcelable!($parcelable < >);
+ };
+ ($parcelable:ident < $( $param:ident ),* , >) => {
+ $crate::impl_deserialize_for_parcelable!($parcelable < $($param),* >);
+ };
+ ($parcelable:ident < $( $param:ident ),* > ) => {
+ impl < $($param: Default),* > $crate::binder_impl::Deserialize for $parcelable < $($param),* > {
fn deserialize(
parcel: &$crate::binder_impl::BorrowedParcel<'_>,
) -> std::result::Result<Self, $crate::StatusCode> {
@@ -830,9 +842,9 @@
}
}
- impl $crate::binder_impl::DeserializeArray for $parcelable {}
+ impl < $($param: Default),* > $crate::binder_impl::DeserializeArray for $parcelable < $($param),* > {}
- impl $crate::binder_impl::DeserializeOption for $parcelable {
+ impl < $($param: Default),* > $crate::binder_impl::DeserializeOption for $parcelable < $($param),* > {
fn deserialize_option(
parcel: &$crate::binder_impl::BorrowedParcel<'_>,
) -> std::result::Result<Option<Self>, $crate::StatusCode> {
diff --git a/libs/binder/tests/IBinderRpcTest.aidl b/libs/binder/tests/IBinderRpcTest.aidl
index a3ed571..1164767 100644
--- a/libs/binder/tests/IBinderRpcTest.aidl
+++ b/libs/binder/tests/IBinderRpcTest.aidl
@@ -80,4 +80,8 @@
// get queued.
oneway void blockingSendFdOneway(in ParcelFileDescriptor fd);
ParcelFileDescriptor blockingRecvFd();
+
+ // Same as blockingSendFdOneway, but with integers.
+ oneway void blockingSendIntOneway(int n);
+ int blockingRecvInt();
}
diff --git a/libs/binder/tests/binderRpcBenchmark.cpp b/libs/binder/tests/binderRpcBenchmark.cpp
index 52ba9b0..5939273 100644
--- a/libs/binder/tests/binderRpcBenchmark.cpp
+++ b/libs/binder/tests/binderRpcBenchmark.cpp
@@ -102,9 +102,11 @@
}
static sp<RpcSession> gSession = RpcSession::make();
+static sp<IBinder> gRpcBinder;
// Certificate validation happens during handshake and does not affect the result of benchmarks.
// Skip certificate validation to simplify the setup process.
static sp<RpcSession> gSessionTls = RpcSession::make(makeFactoryTls());
+static sp<IBinder> gRpcTlsBinder;
#ifdef __BIONIC__
static const String16 kKernelBinderInstance = String16(u"binderRpcBenchmark-control");
static sp<IBinder> gKernelBinder;
@@ -118,9 +120,9 @@
return gKernelBinder;
#endif
case RPC:
- return gSession->getRootObject();
+ return gRpcBinder;
case RPC_TLS:
- return gSessionTls->getRootObject();
+ return gRpcTlsBinder;
default:
LOG(FATAL) << "Unknown transport value: " << transport;
return nullptr;
@@ -254,11 +256,13 @@
(void)unlink(addr.c_str());
forkRpcServer(addr.c_str(), RpcServer::make(RpcTransportCtxFactoryRaw::make()));
setupClient(gSession, addr.c_str());
+ gRpcBinder = gSession->getRootObject();
std::string tlsAddr = tmp + "/binderRpcTlsBenchmark";
(void)unlink(tlsAddr.c_str());
forkRpcServer(tlsAddr.c_str(), RpcServer::make(makeFactoryTls()));
setupClient(gSessionTls, tlsAddr.c_str());
+ gRpcTlsBinder = gSessionTls->getRootObject();
::benchmark::RunSpecifiedBenchmarks();
return 0;
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 5952c41..d563cfc 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -163,7 +163,8 @@
session.root = nullptr;
}
- for (auto& info : sessions) {
+ for (size_t sessionNum = 0; sessionNum < sessions.size(); sessionNum++) {
+ auto& info = sessions.at(sessionNum);
sp<RpcSession>& session = info.session;
EXPECT_NE(nullptr, session);
@@ -179,6 +180,7 @@
for (size_t i = 0; i < 3; i++) {
sp<RpcSession> strongSession = weakSession.promote();
EXPECT_EQ(nullptr, strongSession)
+ << "For session " << sessionNum << ". "
<< (debugBacktrace(host.getPid()), debugBacktrace(getpid()),
"Leaked sess: ")
<< strongSession->getStrongCount() << " checked time " << i;
@@ -231,21 +233,8 @@
return std::move(sockClient);
}
-std::string BinderRpc::PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
- auto [type, security, clientVersion, serverVersion, singleThreaded, noKernel] = info.param;
- auto ret = PrintToString(type) + "_" + newFactory(security)->toCString() + "_clientV" +
- std::to_string(clientVersion) + "_serverV" + std::to_string(serverVersion);
- if (singleThreaded) {
- ret += "_single_threaded";
- } else {
- ret += "_multi_threaded";
- }
- if (noKernel) {
- ret += "_no_kernel";
- } else {
- ret += "_with_kernel";
- }
- return ret;
+std::unique_ptr<RpcTransportCtxFactory> BinderRpc::newFactory(RpcSecurity rpcSecurity) {
+ return newTlsFactory(rpcSecurity);
}
// This creates a new process serving an interface on a certain number of
@@ -254,6 +243,10 @@
const BinderRpcOptions& options) {
CHECK_GE(options.numSessions, 1) << "Must have at least one session to a server";
+ if (options.numIncomingConnectionsBySession.size() != 0) {
+ CHECK_EQ(options.numIncomingConnectionsBySession.size(), options.numSessions);
+ }
+
SocketType socketType = std::get<0>(GetParam());
RpcSecurity rpcSecurity = std::get<1>(GetParam());
uint32_t clientVersion = std::get<2>(GetParam());
@@ -321,7 +314,7 @@
LOG_ALWAYS_FATAL("TIPC socket type only supported on vendor");
#endif
} else {
- factory = newFactory(rpcSecurity, certVerifier);
+ factory = newTlsFactory(rpcSecurity, certVerifier);
}
sessions.emplace_back(RpcSession::make(std::move(factory)));
}
@@ -351,9 +344,15 @@
status_t status;
- for (const auto& session : sessions) {
+ for (size_t i = 0; i < sessions.size(); i++) {
+ const auto& session = sessions.at(i);
+
+ size_t numIncoming = options.numIncomingConnectionsBySession.size() > 0
+ ? options.numIncomingConnectionsBySession.at(i)
+ : 0;
+
CHECK(session->setProtocolVersion(clientVersion));
- session->setMaxIncomingThreads(options.numIncomingConnections);
+ session->setMaxIncomingThreads(numIncoming);
session->setMaxOutgoingConnections(options.numOutgoingConnections);
session->setFileDescriptorTransportMode(options.clientFileDescriptorTransportMode);
@@ -587,30 +586,22 @@
GTEST_SKIP() << "This test requires multiple threads";
}
- constexpr size_t kNumSleeps = 10;
+ constexpr size_t kNumQueued = 10;
constexpr size_t kNumExtraServerThreads = 4;
- constexpr size_t kSleepMs = 50;
// make sure calls to the same object happen on the same thread
auto proc = createRpcTestSocketServerProcess({.numThreads = 1 + kNumExtraServerThreads});
- EXPECT_OK(proc.rootIface->lock());
-
- size_t epochMsBefore = epochMillis();
-
- // all these *Async commands should be queued on the server sequentially,
+ // all these *Oneway commands should be queued on the server sequentially,
// even though there are multiple threads.
- for (size_t i = 0; i + 1 < kNumSleeps; i++) {
- proc.rootIface->sleepMsAsync(kSleepMs);
+ for (size_t i = 0; i + 1 < kNumQueued; i++) {
+ proc.rootIface->blockingSendIntOneway(i);
}
- EXPECT_OK(proc.rootIface->unlockInMsAsync(kSleepMs));
-
- // this can only return once the final async call has unlocked
- EXPECT_OK(proc.rootIface->lockUnlock());
-
- size_t epochMsAfter = epochMillis();
-
- EXPECT_GE(epochMsAfter, epochMsBefore + kSleepMs * kNumSleeps);
+ for (size_t i = 0; i + 1 < kNumQueued; i++) {
+ int n;
+ proc.rootIface->blockingRecvInt(&n);
+ EXPECT_EQ(n, i);
+ }
saturateThreadPool(1 + kNumExtraServerThreads, proc.rootIface);
}
@@ -659,6 +650,32 @@
proc.proc->sessions.erase(proc.proc->sessions.begin() + 1);
}
+TEST_P(BinderRpc, SessionWithIncomingThreadpoolDoesntLeak) {
+ if (clientOrServerSingleThreaded()) {
+ GTEST_SKIP() << "This test requires multiple threads";
+ }
+
+ // session 0 - will check for leaks in destrutor of proc
+ // session 1 - we want to make sure it gets deleted when we drop all references to it
+ auto proc = createRpcTestSocketServerProcess(
+ {.numThreads = 1, .numIncomingConnectionsBySession = {0, 1}, .numSessions = 2});
+
+ wp<RpcSession> session = proc.proc->sessions.at(1).session;
+
+ // remove all references to the second session
+ proc.proc->sessions.at(1).root = nullptr;
+ proc.proc->sessions.erase(proc.proc->sessions.begin() + 1);
+
+ // TODO(b/271830568) more efficient way to wait for other incoming threadpool
+ // to drain commands.
+ for (size_t i = 0; i < 100; i++) {
+ usleep(10 * 1000);
+ if (session.promote() == nullptr) break;
+ }
+
+ EXPECT_EQ(nullptr, session.promote());
+}
+
TEST_P(BinderRpc, SingleDeathRecipient) {
if (clientOrServerSingleThreaded()) {
GTEST_SKIP() << "This test requires multiple threads";
@@ -676,7 +693,7 @@
// Death recipient needs to have an incoming connection to be called
auto proc = createRpcTestSocketServerProcess(
- {.numThreads = 1, .numSessions = 1, .numIncomingConnections = 1});
+ {.numThreads = 1, .numSessions = 1, .numIncomingConnectionsBySession = {1}});
auto dr = sp<MyDeathRec>::make();
ASSERT_EQ(OK, proc.rootBinder->linkToDeath(dr, (void*)1, 0));
@@ -689,6 +706,10 @@
ASSERT_TRUE(dr->mCv.wait_for(lock, 100ms, [&]() { return dr->dead; }));
// need to wait for the session to shutdown so we don't "Leak session"
+ // can't do this before checking the death recipient by calling
+ // forceShutdown earlier, because shutdownAndWait will also trigger
+ // a death recipient, but if we had a way to wait for the service
+ // to gracefully shutdown, we could use that here.
EXPECT_TRUE(proc.proc->sessions.at(0).session->shutdownAndWait(true));
proc.expectAlreadyShutdown = true;
}
@@ -710,7 +731,7 @@
// Death recipient needs to have an incoming connection to be called
auto proc = createRpcTestSocketServerProcess(
- {.numThreads = 1, .numSessions = 1, .numIncomingConnections = 1});
+ {.numThreads = 1, .numSessions = 1, .numIncomingConnectionsBySession = {1}});
auto dr = sp<MyDeathRec>::make();
EXPECT_EQ(OK, proc.rootBinder->linkToDeath(dr, (void*)1, 0));
@@ -743,8 +764,7 @@
void binderDied(const wp<IBinder>& /* who */) override {}
};
- auto proc = createRpcTestSocketServerProcess(
- {.numThreads = 1, .numSessions = 1, .numIncomingConnections = 0});
+ auto proc = createRpcTestSocketServerProcess({.numThreads = 1, .numSessions = 1});
auto dr = sp<MyDeathRec>::make();
EXPECT_EQ(INVALID_OPERATION, proc.rootBinder->linkToDeath(dr, (void*)1, 0));
@@ -763,19 +783,13 @@
// Death recipient needs to have an incoming connection to be called
auto proc = createRpcTestSocketServerProcess(
- {.numThreads = 1, .numSessions = 1, .numIncomingConnections = 1});
+ {.numThreads = 1, .numSessions = 1, .numIncomingConnectionsBySession = {1}});
auto dr = sp<MyDeathRec>::make();
ASSERT_EQ(OK, proc.rootBinder->linkToDeath(dr, (void*)1, 0));
ASSERT_EQ(OK, proc.rootBinder->unlinkToDeath(dr, (void*)1, 0, nullptr));
- if (auto status = proc.rootIface->scheduleShutdown(); !status.isOk()) {
- EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status;
- }
-
- // need to wait for the session to shutdown so we don't "Leak session"
- EXPECT_TRUE(proc.proc->sessions.at(0).session->shutdownAndWait(true));
- proc.expectAlreadyShutdown = true;
+ proc.forceShutdown();
}
TEST_P(BinderRpc, Die) {
@@ -1230,7 +1244,7 @@
};
auto [isStrong1, isStrong2, rpcSecurity] = GetParam();
- auto server = RpcServer::make(newFactory(rpcSecurity));
+ auto server = RpcServer::make(newTlsFactory(rpcSecurity));
auto binder1 = sp<BBinder>::make();
IBinder* binderRaw1 = binder1.get();
setRootObject(isStrong1)(server.get(), binder1);
@@ -1326,7 +1340,7 @@
class BinderRpcServerOnly : public ::testing::TestWithParam<std::tuple<RpcSecurity, uint32_t>> {
public:
static std::string PrintTestParam(const ::testing::TestParamInfo<ParamType>& info) {
- return std::string(newFactory(std::get<0>(info.param))->toCString()) + "_serverV" +
+ return std::string(newTlsFactory(std::get<0>(info.param))->toCString()) + "_serverV" +
std::to_string(std::get<1>(info.param));
}
};
@@ -1334,7 +1348,7 @@
TEST_P(BinderRpcServerOnly, SetExternalServerTest) {
base::unique_fd sink(TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)));
int sinkFd = sink.get();
- auto server = RpcServer::make(newFactory(std::get<0>(GetParam())));
+ auto server = RpcServer::make(newTlsFactory(std::get<0>(GetParam())));
server->setProtocolVersion(std::get<1>(GetParam()));
ASSERT_FALSE(server->hasServer());
ASSERT_EQ(OK, server->setupExternalServer(std::move(sink)));
@@ -1350,7 +1364,7 @@
}
auto addr = allocateSocketAddress();
- auto server = RpcServer::make(newFactory(std::get<0>(GetParam())));
+ auto server = RpcServer::make(newTlsFactory(std::get<0>(GetParam())));
server->setProtocolVersion(std::get<1>(GetParam()));
ASSERT_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
auto joinEnds = std::make_shared<OneOffSignal>();
@@ -1399,7 +1413,7 @@
const Param& param,
std::unique_ptr<RpcAuth> auth = std::make_unique<RpcAuthSelfSigned>()) {
auto [socketType, rpcSecurity, certificateFormat, serverVersion] = param;
- auto rpcServer = RpcServer::make(newFactory(rpcSecurity));
+ auto rpcServer = RpcServer::make(newTlsFactory(rpcSecurity));
rpcServer->setProtocolVersion(serverVersion);
switch (socketType) {
case SocketType::PRECONNECTED: {
@@ -1478,7 +1492,7 @@
}
mFd = rpcServer->releaseServer();
if (!mFd.fd.ok()) return AssertionFailure() << "releaseServer returns invalid fd";
- mCtx = newFactory(rpcSecurity, mCertVerifier, std::move(auth))->newServerCtx();
+ mCtx = newTlsFactory(rpcSecurity, mCertVerifier, std::move(auth))->newServerCtx();
if (mCtx == nullptr) return AssertionFailure() << "newServerCtx";
mSetup = true;
return AssertionSuccess();
@@ -1583,7 +1597,7 @@
auto [socketType, rpcSecurity, certificateFormat, serverVersion] = param;
(void)serverVersion;
mFdTrigger = FdTrigger::make();
- mCtx = newFactory(rpcSecurity, mCertVerifier)->newClientCtx();
+ mCtx = newTlsFactory(rpcSecurity, mCertVerifier)->newClientCtx();
if (mCtx == nullptr) return AssertionFailure() << "newClientCtx";
return AssertionSuccess();
}
@@ -1655,7 +1669,7 @@
using Client = RpcTransportTestUtils::Client;
static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
auto [socketType, rpcSecurity, certificateFormat, serverVersion] = info.param;
- auto ret = PrintToString(socketType) + "_" + newFactory(rpcSecurity)->toCString();
+ auto ret = PrintToString(socketType) + "_" + newTlsFactory(rpcSecurity)->toCString();
if (certificateFormat.has_value()) ret += "_" + PrintToString(*certificateFormat);
ret += "_serverV" + std::to_string(serverVersion);
return ret;
diff --git a/libs/binder/tests/binderRpcTestCommon.h b/libs/binder/tests/binderRpcTestCommon.h
index a467ee3..c1364dd 100644
--- a/libs/binder/tests/binderRpcTestCommon.h
+++ b/libs/binder/tests/binderRpcTestCommon.h
@@ -126,7 +126,11 @@
struct BinderRpcOptions {
size_t numThreads = 1;
size_t numSessions = 1;
- size_t numIncomingConnections = 0;
+ // right now, this can be empty, or length numSessions, where each value
+ // represents the info for the corresponding session, but we should
+ // probably switch this to be a list of sessions options so that other
+ // options can all be specified per session
+ std::vector<size_t> numIncomingConnectionsBySession = {};
size_t numOutgoingConnections = SIZE_MAX;
RpcSession::FileDescriptorTransportMode clientFileDescriptorTransportMode =
RpcSession::FileDescriptorTransportMode::NONE;
@@ -170,7 +174,7 @@
return object;
}
-static inline std::unique_ptr<RpcTransportCtxFactory> newFactory(
+static inline std::unique_ptr<RpcTransportCtxFactory> newTlsFactory(
RpcSecurity rpcSecurity, std::shared_ptr<RpcCertificateVerifier> verifier = nullptr,
std::unique_ptr<RpcAuth> auth = nullptr) {
switch (rpcSecurity) {
@@ -445,6 +449,12 @@
Status blockingRecvFd(android::os::ParcelFileDescriptor* /*fd*/) override {
return Status::fromStatusT(UNKNOWN_TRANSACTION);
}
+
+ Status blockingSendIntOneway(int /*n*/) override {
+ return Status::fromStatusT(UNKNOWN_TRANSACTION);
+ }
+
+ Status blockingRecvInt(int* /*n*/) override { return Status::fromStatusT(UNKNOWN_TRANSACTION); }
};
} // namespace android
diff --git a/libs/binder/tests/binderRpcTestFixture.h b/libs/binder/tests/binderRpcTestFixture.h
index c99d68a..6cde9f7 100644
--- a/libs/binder/tests/binderRpcTestFixture.h
+++ b/libs/binder/tests/binderRpcTestFixture.h
@@ -64,6 +64,21 @@
// whether session should be invalidated by end of run
bool expectAlreadyShutdown = false;
+ // TODO(b/271830568): fix this in binderRpcTest, we always use the first session to cause the
+ // remote process to shutdown. Normally, when we shutdown, the default in the destructor is to
+ // check that there are no leaks and shutdown. However, when there are incoming threadpools,
+ // there will be a few extra binder threads there, so we can't shutdown the server. We should
+ // consider an alternative way of doing the test so that we don't need this, some ideas, such as
+ // program in understanding of incoming threadpool into the destructor so that (e.g.
+ // intelligently wait for sessions to shutdown now that they will do this)
+ void forceShutdown() {
+ if (auto status = rootIface->scheduleShutdown(); !status.isOk()) {
+ EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status;
+ }
+ EXPECT_TRUE(proc->sessions.at(0).session->shutdownAndWait(true));
+ expectAlreadyShutdown = true;
+ }
+
BinderRpcTestProcessSession(BinderRpcTestProcessSession&&) = default;
~BinderRpcTestProcessSession() {
if (!expectAlreadyShutdown) {
@@ -133,9 +148,26 @@
return ret;
}
- static std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info);
+ static std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
+ auto [type, security, clientVersion, serverVersion, singleThreaded, noKernel] = info.param;
+ auto ret = PrintToString(type) + "_" + newFactory(security)->toCString() + "_clientV" +
+ std::to_string(clientVersion) + "_serverV" + std::to_string(serverVersion);
+ if (singleThreaded) {
+ ret += "_single_threaded";
+ } else {
+ ret += "_multi_threaded";
+ }
+ if (noKernel) {
+ ret += "_no_kernel";
+ } else {
+ ret += "_with_kernel";
+ }
+ return ret;
+ }
protected:
+ static std::unique_ptr<RpcTransportCtxFactory> newFactory(RpcSecurity rpcSecurity);
+
std::unique_ptr<ProcessSession> createRpcTestSocketServerProcessEtc(
const BinderRpcOptions& options);
};
diff --git a/libs/binder/tests/binderRpcTestService.cpp b/libs/binder/tests/binderRpcTestService.cpp
index a27bd2f..a9736d5 100644
--- a/libs/binder/tests/binderRpcTestService.cpp
+++ b/libs/binder/tests/binderRpcTestService.cpp
@@ -83,6 +83,18 @@
fd->reset(mFdChannel.read());
return Status::ok();
}
+
+ HandoffChannel<int> mIntChannel;
+
+ Status blockingSendIntOneway(int n) override {
+ mIntChannel.write(n);
+ return Status::ok();
+ }
+
+ Status blockingRecvInt(int* n) override {
+ *n = mIntChannel.read();
+ return Status::ok();
+ }
};
int main(int argc, char* argv[]) {
@@ -104,7 +116,7 @@
}
auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
- sp<RpcServer> server = RpcServer::make(newFactory(rpcSecurity, certVerifier));
+ sp<RpcServer> server = RpcServer::make(newTlsFactory(rpcSecurity, certVerifier));
server->setProtocolVersion(serverConfig.serverVersion);
server->setMaxThreads(serverConfig.numThreads);
diff --git a/libs/binder/tests/binderRpcTestTrusty.cpp b/libs/binder/tests/binderRpcTestTrusty.cpp
index 63b56a3..28be10d 100644
--- a/libs/binder/tests/binderRpcTestTrusty.cpp
+++ b/libs/binder/tests/binderRpcTestTrusty.cpp
@@ -39,31 +39,25 @@
void terminate() override { LOG_ALWAYS_FATAL("terminate() not supported"); }
};
-std::string BinderRpc::PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
- auto [type, security, clientVersion, serverVersion, singleThreaded, noKernel] = info.param;
- auto ret = PrintToString(type) + "_clientV" + std::to_string(clientVersion) + "_serverV" +
- std::to_string(serverVersion);
- if (singleThreaded) {
- ret += "_single_threaded";
- } else {
- ret += "_multi_threaded";
+std::unique_ptr<RpcTransportCtxFactory> BinderRpc::newFactory(RpcSecurity rpcSecurity) {
+ switch (rpcSecurity) {
+ case RpcSecurity::RAW:
+ return RpcTransportCtxFactoryTipcTrusty::make();
+ default:
+ LOG_ALWAYS_FATAL("Unknown RpcSecurity %d", rpcSecurity);
}
- if (noKernel) {
- ret += "_no_kernel";
- } else {
- ret += "_with_kernel";
- }
- return ret;
}
// This creates a new process serving an interface on a certain number of
// threads.
std::unique_ptr<ProcessSession> BinderRpc::createRpcTestSocketServerProcessEtc(
const BinderRpcOptions& options) {
- LOG_ALWAYS_FATAL_IF(options.numIncomingConnections != 0,
- "Non-zero incoming connections %zu on Trusty",
- options.numIncomingConnections);
+ LOG_ALWAYS_FATAL_IF(std::any_of(options.numIncomingConnectionsBySession.begin(),
+ options.numIncomingConnectionsBySession.end(),
+ [](size_t n) { return n != 0; }),
+ "Non-zero incoming connections on Trusty");
+ RpcSecurity rpcSecurity = std::get<1>(GetParam());
uint32_t clientVersion = std::get<2>(GetParam());
uint32_t serverVersion = std::get<3>(GetParam());
@@ -71,8 +65,7 @@
status_t status;
for (size_t i = 0; i < options.numSessions; i++) {
- auto factory = android::RpcTransportCtxFactoryTipcTrusty::make();
- auto session = android::RpcSession::make(std::move(factory));
+ auto session = android::RpcSession::make(newFactory(rpcSecurity));
EXPECT_TRUE(session->setProtocolVersion(clientVersion));
session->setMaxOutgoingConnections(options.numOutgoingConnections);
diff --git a/libs/binder/tests/binderRpcUniversalTests.cpp b/libs/binder/tests/binderRpcUniversalTests.cpp
index 11a22b0..1f46010 100644
--- a/libs/binder/tests/binderRpcUniversalTests.cpp
+++ b/libs/binder/tests/binderRpcUniversalTests.cpp
@@ -463,7 +463,7 @@
auto proc = createRpcTestSocketServerProcess(
{.numThreads = 1,
.numSessions = 1,
- .numIncomingConnections = numIncomingConnections});
+ .numIncomingConnectionsBySession = {numIncomingConnections}});
auto cb = sp<MyBinderRpcCallback>::make();
if (callIsOneway) {
@@ -491,16 +491,7 @@
<< "callIsOneway: " << callIsOneway
<< " callbackIsOneway: " << callbackIsOneway << " delayed: " << delayed;
- // since we are severing the connection, we need to go ahead and
- // tell the server to shutdown and exit so that waitpid won't hang
- if (auto status = proc.rootIface->scheduleShutdown(); !status.isOk()) {
- EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status;
- }
-
- // since this session has an incoming connection w/ a threadpool, we
- // need to manually shut it down
- EXPECT_TRUE(proc.proc->sessions.at(0).session->shutdownAndWait(true));
- proc.expectAlreadyShutdown = true;
+ proc.forceShutdown();
}
}
}
diff --git a/libs/binder/tests/unit_fuzzers/RecordedTransactionFileFuzz.cpp b/libs/binder/tests/unit_fuzzers/RecordedTransactionFileFuzz.cpp
index 73790fa..e494366 100644
--- a/libs/binder/tests/unit_fuzzers/RecordedTransactionFileFuzz.cpp
+++ b/libs/binder/tests/unit_fuzzers/RecordedTransactionFileFuzz.cpp
@@ -26,7 +26,7 @@
rewind(intermediateFile);
int fileNumber = fileno(intermediateFile);
- android::base::unique_fd fd(fileNumber);
+ android::base::unique_fd fd(dup(fileNumber));
auto transaction = android::binder::debug::RecordedTransaction::fromFile(fd);
diff --git a/libs/binderdebug/Android.bp b/libs/binderdebug/Android.bp
index 3eeaf3e..1454727 100644
--- a/libs/binderdebug/Android.bp
+++ b/libs/binderdebug/Android.bp
@@ -21,6 +21,17 @@
default_applicable_licenses: ["frameworks_native_license"],
}
+cc_benchmark {
+ name: "binder_thread_stats",
+ shared_libs: [
+ "libutils",
+ "libbinder",
+ "libbase",
+ ],
+ static_libs: ["libbinderdebug"],
+ srcs: ["stats.cpp"],
+}
+
cc_library {
name: "libbinderdebug",
vendor_available: true,
diff --git a/libs/binderdebug/stats.cpp b/libs/binderdebug/stats.cpp
new file mode 100644
index 0000000..9c26afa
--- /dev/null
+++ b/libs/binderdebug/stats.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <binder/BpBinder.h>
+#include <binder/IServiceManager.h>
+#include <binderdebug/BinderDebug.h>
+#include <utils/Errors.h>
+
+#include <inttypes.h>
+
+namespace android {
+
+extern "C" int main() {
+ // ignore args - we only print csv
+
+ // we should use a csv library here for escaping, because
+ // the name is coming from another process
+ printf("name,binder_threads_in_use,binder_threads_started,client_count\n");
+
+ for (const String16& name : defaultServiceManager()->listServices()) {
+ sp<IBinder> binder = defaultServiceManager()->checkService(name);
+ if (binder == nullptr) {
+ fprintf(stderr, "%s is null", String8(name).c_str());
+ continue;
+ }
+
+ BpBinder* remote = binder->remoteBinder();
+ const auto handle = remote->getDebugBinderHandle();
+ CHECK(handle != std::nullopt);
+
+ pid_t pid;
+ CHECK_EQ(OK, binder->getDebugPid(&pid));
+
+ BinderPidInfo info;
+ CHECK_EQ(OK, getBinderPidInfo(BinderDebugContext::BINDER, pid, &info));
+
+ std::vector<pid_t> clientPids;
+ CHECK_EQ(OK,
+ getBinderClientPids(BinderDebugContext::BINDER, getpid(), pid, *handle,
+ &clientPids));
+
+ printf("%s,%" PRIu32 ",%" PRIu32 ",%zu\n", String8(name).c_str(), info.threadUsage,
+ info.threadCount, clientPids.size());
+ }
+ return 0;
+}
+
+} // namespace android
diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp
index 8e57152..ea1b5e4 100644
--- a/libs/ftl/Android.bp
+++ b/libs/ftl/Android.bp
@@ -10,9 +10,6 @@
cc_test {
name: "ftl_test",
test_suites: ["device-tests"],
- sanitize: {
- address: true,
- },
srcs: [
"algorithm_test.cpp",
"cast_test.cpp",
diff --git a/libs/ftl/TEST_MAPPING b/libs/ftl/TEST_MAPPING
new file mode 100644
index 0000000..ec0c671
--- /dev/null
+++ b/libs/ftl/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "ftl_test"
+ }
+ ],
+ "hwasan-presubmit": [
+ {
+ "name": "ftl_test"
+ }
+ ]
+}
diff --git a/libs/ftl/optional_test.cpp b/libs/ftl/optional_test.cpp
index 6b3b6c4..91bf7bc 100644
--- a/libs/ftl/optional_test.cpp
+++ b/libs/ftl/optional_test.cpp
@@ -164,6 +164,46 @@
}));
}
+TEST(Optional, OrElse) {
+ // Non-empty.
+ {
+ const Optional opt = false;
+ EXPECT_EQ(false, opt.or_else([] { return Optional(true); }));
+ EXPECT_EQ('x', Optional('x').or_else([] { return std::make_optional('y'); }));
+ }
+
+ // Empty.
+ {
+ const Optional<int> opt;
+ EXPECT_EQ(123, opt.or_else([]() -> Optional<int> { return 123; }));
+ EXPECT_EQ("abc"s, Optional<std::string>().or_else([] { return Optional("abc"s); }));
+ }
+ {
+ bool empty = false;
+ EXPECT_EQ(Optional<float>(), Optional<float>().or_else([&empty]() -> Optional<float> {
+ empty = true;
+ return std::nullopt;
+ }));
+ EXPECT_TRUE(empty);
+ }
+
+ // Chaining.
+ using StringVector = StaticVector<std::string, 3>;
+ EXPECT_EQ(999, Optional(StaticVector{"1"s, "0"s, "0"s})
+ .and_then([](StringVector&& v) -> Optional<StringVector> {
+ if (v.push_back("0"s)) return v;
+ return {};
+ })
+ .or_else([] {
+ return Optional(StaticVector{"9"s, "9"s, "9"s});
+ })
+ .transform([](const StringVector& v) {
+ return std::accumulate(v.begin(), v.end(), std::string());
+ })
+ .and_then(parse_int)
+ .or_else([] { return Optional(-1); }));
+}
+
// Comparison.
namespace {
diff --git a/libs/gui/aidl/android/gui/IHdrLayerInfoListener.aidl b/libs/gui/aidl/android/gui/IHdrLayerInfoListener.aidl
index fc809c4..e8c36ee 100644
--- a/libs/gui/aidl/android/gui/IHdrLayerInfoListener.aidl
+++ b/libs/gui/aidl/android/gui/IHdrLayerInfoListener.aidl
@@ -19,7 +19,9 @@
/** @hide */
oneway interface IHdrLayerInfoListener {
// Callback with the total number of HDR layers, the dimensions of the largest layer,
- // and a placeholder flags
+ // a placeholder flags, and the max desired HDR/SDR ratio. The max desired HDR/SDR
+ // ratio may be positive infinity to indicate an unbounded ratio.
// TODO (b/182312559): Define the flags (likely need an indicator that a UDFPS layer is present)
- void onHdrLayerInfoChanged(int numberOfHdrLayers, int maxW, int maxH, int flags);
+ void onHdrLayerInfoChanged(int numberOfHdrLayers, int maxW, int maxH,
+ int flags, float maxDesiredHdrSdrRatio);
}
\ No newline at end of file
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 133b260..53b22cb 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -151,10 +151,23 @@
// --- InputEvent ---
+// Due to precision limitations when working with floating points, transforming - namely
+// scaling - floating points can lead to minute errors. We round transformed values to approximately
+// three decimal places so that values like 0.99997 show up as 1.0.
+inline float roundTransformedCoords(float val) {
+ // Use a power to two to approximate three decimal places to potentially reduce some cycles.
+ // This should be at least as precise as MotionEvent::ROUNDING_PRECISION.
+ return std::round(val * 1024.f) / 1024.f;
+}
+
+inline vec2 roundTransformedCoords(vec2 p) {
+ return {roundTransformedCoords(p.x), roundTransformedCoords(p.y)};
+}
+
vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy) {
const vec2 transformedXy = transform.transform(xy);
const vec2 transformedOrigin = transform.transform(0, 0);
- return transformedXy - transformedOrigin;
+ return roundTransformedCoords(transformedXy - transformedOrigin);
}
float transformAngle(const ui::Transform& transform, float angleRadians) {
@@ -606,12 +619,12 @@
float MotionEvent::getXCursorPosition() const {
vec2 vals = mTransform.transform(getRawXCursorPosition(), getRawYCursorPosition());
- return vals.x;
+ return roundTransformedCoords(vals.x);
}
float MotionEvent::getYCursorPosition() const {
vec2 vals = mTransform.transform(getRawXCursorPosition(), getRawYCursorPosition());
- return vals.y;
+ return roundTransformedCoords(vals.y);
}
void MotionEvent::setCursorPosition(float x, float y) {
@@ -933,7 +946,7 @@
static inline vec2 calculateTransformedXYUnchecked(uint32_t source, const ui::Transform& transform,
const vec2& xy) {
return shouldDisregardOffset(source) ? transformWithoutTranslation(transform, xy)
- : transform.transform(xy);
+ : roundTransformedCoords(transform.transform(xy));
}
vec2 MotionEvent::calculateTransformedXY(uint32_t source, const ui::Transform& transform,
diff --git a/libs/input/Keyboard.cpp b/libs/input/Keyboard.cpp
index 3f8467d..0b5c7ff 100644
--- a/libs/input/Keyboard.cpp
+++ b/libs/input/Keyboard.cpp
@@ -16,9 +16,10 @@
#define LOG_TAG "Keyboard"
+#include <limits.h>
#include <stdlib.h>
#include <unistd.h>
-#include <limits.h>
+#include <optional>
#include <input/InputDevice.h>
#include <input/InputEventLabels.h>
@@ -49,23 +50,25 @@
const PropertyMap* deviceConfiguration) {
// Use the configured key layout if available.
if (deviceConfiguration) {
- std::string keyLayoutName;
- if (deviceConfiguration->tryGetProperty("keyboard.layout", keyLayoutName)) {
- status_t status = loadKeyLayout(deviceIdentifier, keyLayoutName.c_str());
+ std::optional<std::string> keyLayoutName =
+ deviceConfiguration->getString("keyboard.layout");
+ if (keyLayoutName.has_value()) {
+ status_t status = loadKeyLayout(deviceIdentifier, *keyLayoutName);
if (status == NAME_NOT_FOUND) {
ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but "
"it was not found.",
- deviceIdentifier.name.c_str(), keyLayoutName.c_str());
+ deviceIdentifier.name.c_str(), keyLayoutName->c_str());
}
}
- std::string keyCharacterMapName;
- if (deviceConfiguration->tryGetProperty("keyboard.characterMap", keyCharacterMapName)) {
- status_t status = loadKeyCharacterMap(deviceIdentifier, keyCharacterMapName.c_str());
+ std::optional<std::string> keyCharacterMapName =
+ deviceConfiguration->getString("keyboard.characterMap");
+ if (keyCharacterMapName.has_value()) {
+ status_t status = loadKeyCharacterMap(deviceIdentifier, *keyCharacterMapName);
if (status == NAME_NOT_FOUND) {
ALOGE("Configuration for keyboard device '%s' requested keyboard character "
"map '%s' but it was not found.",
- deviceIdentifier.name.c_str(), keyCharacterMapName.c_str());
+ deviceIdentifier.name.c_str(), keyCharacterMapName->c_str());
}
}
@@ -162,9 +165,7 @@
if (config == nullptr) {
return false;
}
- bool isSpecialFunction = false;
- config->tryGetProperty("keyboard.specialFunction", isSpecialFunction);
- return isSpecialFunction;
+ return config->getBool("keyboard.specialFunction").value_or(false);
}
bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier,
@@ -177,8 +178,7 @@
}
if (deviceConfiguration) {
- bool builtIn = false;
- if (deviceConfiguration->tryGetProperty("keyboard.builtIn", builtIn) && builtIn) {
+ if (deviceConfiguration->getBool("keyboard.builtIn").value_or(false)) {
return true;
}
}
diff --git a/libs/input/PropertyMap.cpp b/libs/input/PropertyMap.cpp
index 9a4f10b..548f894 100644
--- a/libs/input/PropertyMap.cpp
+++ b/libs/input/PropertyMap.cpp
@@ -60,75 +60,62 @@
return mProperties.find(key) != mProperties.end();
}
-bool PropertyMap::tryGetProperty(const std::string& key, std::string& outValue) const {
+std::optional<std::string> PropertyMap::getString(const std::string& key) const {
auto it = mProperties.find(key);
- if (it == mProperties.end()) {
- return false;
- }
-
- outValue = it->second;
- return true;
+ return it != mProperties.end() ? std::make_optional(it->second) : std::nullopt;
}
-bool PropertyMap::tryGetProperty(const std::string& key, bool& outValue) const {
- int32_t intValue;
- if (!tryGetProperty(key, intValue)) {
- return false;
- }
-
- outValue = intValue;
- return true;
+std::optional<bool> PropertyMap::getBool(const std::string& key) const {
+ std::optional<int32_t> intValue = getInt(key);
+ return intValue.has_value() ? std::make_optional(*intValue != 0) : std::nullopt;
}
-bool PropertyMap::tryGetProperty(const std::string& key, int32_t& outValue) const {
- std::string stringValue;
- if (!tryGetProperty(key, stringValue) || stringValue.length() == 0) {
- return false;
+std::optional<int32_t> PropertyMap::getInt(const std::string& key) const {
+ std::optional<std::string> stringValue = getString(key);
+ if (!stringValue.has_value() || stringValue->length() == 0) {
+ return std::nullopt;
}
char* end;
- int32_t value = static_cast<int32_t>(strtol(stringValue.c_str(), &end, 10));
+ int32_t value = static_cast<int32_t>(strtol(stringValue->c_str(), &end, 10));
if (*end != '\0') {
ALOGW("Property key '%s' has invalid value '%s'. Expected an integer.", key.c_str(),
- stringValue.c_str());
- return false;
+ stringValue->c_str());
+ return std::nullopt;
}
- outValue = value;
- return true;
+ return value;
}
-bool PropertyMap::tryGetProperty(const std::string& key, float& outValue) const {
- std::string stringValue;
- if (!tryGetProperty(key, stringValue) || stringValue.length() == 0) {
- return false;
+std::optional<float> PropertyMap::getFloat(const std::string& key) const {
+ std::optional<std::string> stringValue = getString(key);
+ if (!stringValue.has_value() || stringValue->length() == 0) {
+ return std::nullopt;
}
char* end;
- float value = strtof(stringValue.c_str(), &end);
+ float value = strtof(stringValue->c_str(), &end);
if (*end != '\0') {
ALOGW("Property key '%s' has invalid value '%s'. Expected a float.", key.c_str(),
- stringValue.c_str());
- return false;
+ stringValue->c_str());
+ return std::nullopt;
}
- outValue = value;
- return true;
+ return value;
}
-bool PropertyMap::tryGetProperty(const std::string& key, double& outValue) const {
- std::string stringValue;
- if (!tryGetProperty(key, stringValue) || stringValue.length() == 0) {
- return false;
+std::optional<double> PropertyMap::getDouble(const std::string& key) const {
+ std::optional<std::string> stringValue = getString(key);
+ if (!stringValue.has_value() || stringValue->length() == 0) {
+ return std::nullopt;
}
char* end;
- double value = strtod(stringValue.c_str(), &end);
+ double value = strtod(stringValue->c_str(), &end);
if (*end != '\0') {
ALOGW("Property key '%s' has invalid value '%s'. Expected a double.", key.c_str(),
- stringValue.c_str());
- return false;
+ stringValue->c_str());
+ return std::nullopt;
}
- outValue = value;
- return true;
+ return value;
}
void PropertyMap::addAll(const PropertyMap* map) {
diff --git a/libs/input/PropertyMap_fuzz.cpp b/libs/input/PropertyMap_fuzz.cpp
old mode 100755
new mode 100644
index d985dc1..6299ca8
--- a/libs/input/PropertyMap_fuzz.cpp
+++ b/libs/input/PropertyMap_fuzz.cpp
@@ -29,8 +29,7 @@
},
[](FuzzedDataProvider* dataProvider, android::PropertyMap& propertyMap) -> void {
std::string key = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN);
- std::string out;
- propertyMap.tryGetProperty(key, out);
+ propertyMap.getString(key);
},
[](FuzzedDataProvider* dataProvider, android::PropertyMap& /*unused*/) -> void {
TemporaryFile tf;
diff --git a/libs/input/TfLiteMotionPredictor.cpp b/libs/input/TfLiteMotionPredictor.cpp
index 691e87c..3b061d1 100644
--- a/libs/input/TfLiteMotionPredictor.cpp
+++ b/libs/input/TfLiteMotionPredictor.cpp
@@ -61,8 +61,21 @@
constexpr char OUTPUT_PHI[] = "phi";
constexpr char OUTPUT_PRESSURE[] = "pressure";
+// Ideally, we would just use std::filesystem::exists here, but it requires libc++fs, which causes
+// build issues in other parts of the system.
+#if defined(__ANDROID__)
+bool fileExists(const char* filename) {
+ struct stat buffer;
+ return stat(filename, &buffer) == 0;
+}
+#endif
+
std::string getModelPath() {
#if defined(__ANDROID__)
+ static const char* oemModel = "/vendor/etc/motion_predictor_model.fb";
+ if (fileExists(oemModel)) {
+ return oemModel;
+ }
return "/system/etc/motion_predictor_model.fb";
#else
return base::GetExecutableDirectory() + "/motion_predictor_model.fb";
@@ -217,7 +230,7 @@
std::unique_ptr<TfLiteMotionPredictorModel> TfLiteMotionPredictorModel::create() {
const std::string modelPath = getModelPath();
- const int fd = open(modelPath.c_str(), O_RDONLY);
+ android::base::unique_fd fd(open(modelPath.c_str(), O_RDONLY));
if (fd == -1) {
PLOG(FATAL) << "Could not read model from " << modelPath;
}
@@ -232,9 +245,6 @@
if (!modelBuffer) {
PLOG(FATAL) << "Failed to mmap model";
}
- if (close(fd) == -1) {
- PLOG(FATAL) << "Failed to close model fd";
- }
return std::unique_ptr<TfLiteMotionPredictorModel>(
new TfLiteMotionPredictorModel(std::move(modelBuffer)));
diff --git a/libs/input/TouchVideoFrame.cpp b/libs/input/TouchVideoFrame.cpp
index c9393f4..6d7d561 100644
--- a/libs/input/TouchVideoFrame.cpp
+++ b/libs/input/TouchVideoFrame.cpp
@@ -43,13 +43,13 @@
void TouchVideoFrame::rotate(ui::Rotation orientation) {
switch (orientation) {
case ui::ROTATION_90:
- rotateQuarterTurn(false /*clockwise*/);
+ rotateQuarterTurn(/*clockwise=*/false);
break;
case ui::ROTATION_180:
rotate180();
break;
case ui::ROTATION_270:
- rotateQuarterTurn(true /*clockwise*/);
+ rotateQuarterTurn(/*clockwise=*/true);
break;
case ui::ROTATION_0:
// No need to rotate if there's no rotation.
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index 3632914..8551e5f 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -157,10 +157,10 @@
std::unique_ptr<VelocityTrackerStrategy> createdStrategy;
if (mOverrideStrategy != VelocityTracker::Strategy::DEFAULT) {
- createdStrategy = createStrategy(mOverrideStrategy, isDifferentialAxis /* deltaValues */);
+ createdStrategy = createStrategy(mOverrideStrategy, /*deltaValues=*/isDifferentialAxis);
} else {
createdStrategy = createStrategy(DEFAULT_STRATEGY_BY_AXIS.at(axis),
- isDifferentialAxis /* deltaValues */);
+ /*deltaValues=*/isDifferentialAxis);
}
LOG_ALWAYS_FATAL_IF(createdStrategy == nullptr,
@@ -495,7 +495,7 @@
}
ALOGD_IF(DEBUG_STRATEGY, " - a=%s",
- matrixToString(&a[0][0], m, n, false /*rowMajor*/).c_str());
+ matrixToString(&a[0][0], m, n, /*rowMajor=*/false).c_str());
// Apply the Gram-Schmidt process to A to obtain its QR decomposition.
float q[n][m]; // orthonormal basis, column-major order
@@ -527,8 +527,8 @@
}
}
if (DEBUG_STRATEGY) {
- ALOGD(" - q=%s", matrixToString(&q[0][0], m, n, false /*rowMajor*/).c_str());
- ALOGD(" - r=%s", matrixToString(&r[0][0], n, n, true /*rowMajor*/).c_str());
+ ALOGD(" - q=%s", matrixToString(&q[0][0], m, n, /*rowMajor=*/false).c_str());
+ ALOGD(" - r=%s", matrixToString(&r[0][0], n, n, /*rowMajor=*/true).c_str());
// calculate QR, if we factored A correctly then QR should equal A
float qr[n][m];
@@ -540,7 +540,7 @@
}
}
}
- ALOGD(" - qr=%s", matrixToString(&qr[0][0], m, n, false /*rowMajor*/).c_str());
+ ALOGD(" - qr=%s", matrixToString(&qr[0][0], m, n, /*rowMajor=*/false).c_str());
}
// Solve R B = Qt W Y to find B. This is easy because R is upper triangular.
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index 8a6e983..2132dc1 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -29,6 +29,8 @@
// Default display id.
static constexpr int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT;
+static constexpr float EPSILON = MotionEvent::ROUNDING_PRECISION;
+
class BaseTest : public testing::Test {
protected:
static constexpr std::array<uint8_t, 32> HMAC = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
@@ -235,102 +237,110 @@
static constexpr float RAW_X_OFFSET = 12;
static constexpr float RAW_Y_OFFSET = -41.1;
+ void SetUp() override;
+
int32_t mId;
ui::Transform mTransform;
ui::Transform mRawTransform;
+ PointerProperties mPointerProperties[2];
+ struct Sample {
+ PointerCoords pointerCoords[2];
+ };
+ std::array<Sample, 3> mSamples{};
void initializeEventWithHistory(MotionEvent* event);
void assertEqualsEventWithHistory(const MotionEvent* event);
};
-void MotionEventTest::initializeEventWithHistory(MotionEvent* event) {
+void MotionEventTest::SetUp() {
mId = InputEvent::nextId();
mTransform.set({X_SCALE, 0, X_OFFSET, 0, Y_SCALE, Y_OFFSET, 0, 0, 1});
mRawTransform.set({RAW_X_SCALE, 0, RAW_X_OFFSET, 0, RAW_Y_SCALE, RAW_Y_OFFSET, 0, 0, 1});
- PointerProperties pointerProperties[2];
- pointerProperties[0].clear();
- pointerProperties[0].id = 1;
- pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
- pointerProperties[1].clear();
- pointerProperties[1].id = 2;
- pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+ mPointerProperties[0].clear();
+ mPointerProperties[0].id = 1;
+ mPointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+ mPointerProperties[1].clear();
+ mPointerProperties[1].id = 2;
+ mPointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
- PointerCoords pointerCoords[2];
- pointerCoords[0].clear();
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 10);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 11);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 12);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 13);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 14);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 15);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 16);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 17);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 18);
- pointerCoords[0].isResampled = true;
- pointerCoords[1].clear();
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 20);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 21);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 22);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 23);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 24);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 25);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 26);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 27);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28);
+ mSamples[0].pointerCoords[0].clear();
+ mSamples[0].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 10);
+ mSamples[0].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 11);
+ mSamples[0].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 12);
+ mSamples[0].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 13);
+ mSamples[0].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 14);
+ mSamples[0].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 15);
+ mSamples[0].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 16);
+ mSamples[0].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 17);
+ mSamples[0].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 18);
+ mSamples[0].pointerCoords[0].isResampled = true;
+ mSamples[0].pointerCoords[1].clear();
+ mSamples[0].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 20);
+ mSamples[0].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 21);
+ mSamples[0].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 22);
+ mSamples[0].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 23);
+ mSamples[0].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 24);
+ mSamples[0].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 25);
+ mSamples[0].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 26);
+ mSamples[0].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 27);
+ mSamples[0].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28);
+
+ mSamples[1].pointerCoords[0].clear();
+ mSamples[1].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 110);
+ mSamples[1].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 111);
+ mSamples[1].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 112);
+ mSamples[1].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 113);
+ mSamples[1].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 114);
+ mSamples[1].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 115);
+ mSamples[1].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 116);
+ mSamples[1].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 117);
+ mSamples[1].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 118);
+ mSamples[1].pointerCoords[0].isResampled = true;
+ mSamples[1].pointerCoords[1].clear();
+ mSamples[1].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 120);
+ mSamples[1].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 121);
+ mSamples[1].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 122);
+ mSamples[1].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 123);
+ mSamples[1].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 124);
+ mSamples[1].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 125);
+ mSamples[1].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 126);
+ mSamples[1].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 127);
+ mSamples[1].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 128);
+ mSamples[1].pointerCoords[1].isResampled = true;
+
+ mSamples[2].pointerCoords[0].clear();
+ mSamples[2].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 210);
+ mSamples[2].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 211);
+ mSamples[2].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 212);
+ mSamples[2].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 213);
+ mSamples[2].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 214);
+ mSamples[2].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 215);
+ mSamples[2].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 216);
+ mSamples[2].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 217);
+ mSamples[2].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 218);
+ mSamples[2].pointerCoords[1].clear();
+ mSamples[2].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 220);
+ mSamples[2].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 221);
+ mSamples[2].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 222);
+ mSamples[2].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 223);
+ mSamples[2].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 224);
+ mSamples[2].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 225);
+ mSamples[2].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 226);
+ mSamples[2].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 227);
+ mSamples[2].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 228);
+}
+
+void MotionEventTest::initializeEventWithHistory(MotionEvent* event) {
event->initialize(mId, 2, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, HMAC,
AMOTION_EVENT_ACTION_MOVE, 0, AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED,
AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY,
MotionClassification::NONE, mTransform, 2.0f, 2.1f,
AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
mRawTransform, ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME, 2,
- pointerProperties, pointerCoords);
-
- pointerCoords[0].clear();
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 110);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 111);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 112);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 113);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 114);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 115);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 116);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 117);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 118);
- pointerCoords[0].isResampled = true;
- pointerCoords[1].clear();
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 120);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 121);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 122);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 123);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 124);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 125);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 126);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 127);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 128);
- pointerCoords[1].isResampled = true;
- event->addSample(ARBITRARY_EVENT_TIME + 1, pointerCoords);
-
- pointerCoords[0].clear();
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 210);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 211);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 212);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 213);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 214);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 215);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 216);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 217);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 218);
- pointerCoords[1].clear();
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 220);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 221);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 222);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 223);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 224);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 225);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 226);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 227);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 228);
- event->addSample(ARBITRARY_EVENT_TIME + 2, pointerCoords);
+ mPointerProperties, mSamples[0].pointerCoords);
+ event->addSample(ARBITRARY_EVENT_TIME + 1, mSamples[1].pointerCoords);
+ event->addSample(ARBITRARY_EVENT_TIME + 2, mSamples[2].pointerCoords);
}
void MotionEventTest::assertEqualsEventWithHistory(const MotionEvent* event) {
@@ -367,51 +377,65 @@
ASSERT_EQ(ARBITRARY_EVENT_TIME + 1, event->getHistoricalEventTime(1));
ASSERT_EQ(ARBITRARY_EVENT_TIME + 2, event->getEventTime());
- ASSERT_EQ(11, event->getHistoricalRawPointerCoords(0, 0)->getAxisValue(AMOTION_EVENT_AXIS_Y));
- ASSERT_EQ(21, event->getHistoricalRawPointerCoords(1, 0)->getAxisValue(AMOTION_EVENT_AXIS_Y));
- ASSERT_EQ(111, event->getHistoricalRawPointerCoords(0, 1)->getAxisValue(AMOTION_EVENT_AXIS_Y));
- ASSERT_EQ(121, event->getHistoricalRawPointerCoords(1, 1)->getAxisValue(AMOTION_EVENT_AXIS_Y));
- ASSERT_EQ(211, event->getRawPointerCoords(0)->getAxisValue(AMOTION_EVENT_AXIS_Y));
- ASSERT_EQ(221, event->getRawPointerCoords(1)->getAxisValue(AMOTION_EVENT_AXIS_Y));
+ // Ensure the underlying PointerCoords are identical.
+ for (int sampleIdx = 0; sampleIdx < 3; sampleIdx++) {
+ for (int pointerIdx = 0; pointerIdx < 2; pointerIdx++) {
+ ASSERT_EQ(mSamples[sampleIdx].pointerCoords[pointerIdx],
+ event->getSamplePointerCoords()[sampleIdx * 2 + pointerIdx]);
+ }
+ }
- ASSERT_EQ(RAW_Y_OFFSET + 11 * RAW_Y_SCALE,
- event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 0));
- ASSERT_EQ(RAW_Y_OFFSET + 21 * RAW_Y_SCALE,
- event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 0));
- ASSERT_EQ(RAW_Y_OFFSET + 111 * RAW_Y_SCALE,
- event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 1));
- ASSERT_EQ(RAW_Y_OFFSET + 121 * RAW_Y_SCALE,
- event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 1));
- ASSERT_EQ(RAW_Y_OFFSET + 211 * RAW_Y_SCALE, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 0));
- ASSERT_EQ(RAW_Y_OFFSET + 221 * RAW_Y_SCALE, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 1));
+ ASSERT_NEAR(11, event->getHistoricalRawPointerCoords(0, 0)->getAxisValue(AMOTION_EVENT_AXIS_Y),
+ EPSILON);
+ ASSERT_NEAR(21, event->getHistoricalRawPointerCoords(1, 0)->getAxisValue(AMOTION_EVENT_AXIS_Y),
+ EPSILON);
+ ASSERT_NEAR(111, event->getHistoricalRawPointerCoords(0, 1)->getAxisValue(AMOTION_EVENT_AXIS_Y),
+ EPSILON);
+ ASSERT_NEAR(121, event->getHistoricalRawPointerCoords(1, 1)->getAxisValue(AMOTION_EVENT_AXIS_Y),
+ EPSILON);
+ ASSERT_NEAR(211, event->getRawPointerCoords(0)->getAxisValue(AMOTION_EVENT_AXIS_Y), EPSILON);
+ ASSERT_NEAR(221, event->getRawPointerCoords(1)->getAxisValue(AMOTION_EVENT_AXIS_Y), EPSILON);
- ASSERT_EQ(RAW_X_OFFSET + 10 * RAW_X_SCALE, event->getHistoricalRawX(0, 0));
- ASSERT_EQ(RAW_X_OFFSET + 20 * RAW_X_SCALE, event->getHistoricalRawX(1, 0));
- ASSERT_EQ(RAW_X_OFFSET + 110 * RAW_X_SCALE, event->getHistoricalRawX(0, 1));
- ASSERT_EQ(RAW_X_OFFSET + 120 * RAW_X_SCALE, event->getHistoricalRawX(1, 1));
- ASSERT_EQ(RAW_X_OFFSET + 210 * RAW_X_SCALE, event->getRawX(0));
- ASSERT_EQ(RAW_X_OFFSET + 220 * RAW_X_SCALE, event->getRawX(1));
+ ASSERT_NEAR(RAW_Y_OFFSET + 11 * RAW_Y_SCALE,
+ event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 0), EPSILON);
+ ASSERT_NEAR(RAW_Y_OFFSET + 21 * RAW_Y_SCALE,
+ event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 0), EPSILON);
+ ASSERT_NEAR(RAW_Y_OFFSET + 111 * RAW_Y_SCALE,
+ event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 1), EPSILON);
+ ASSERT_NEAR(RAW_Y_OFFSET + 121 * RAW_Y_SCALE,
+ event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 1), EPSILON);
+ ASSERT_NEAR(RAW_Y_OFFSET + 211 * RAW_Y_SCALE, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 0),
+ EPSILON);
+ ASSERT_NEAR(RAW_Y_OFFSET + 221 * RAW_Y_SCALE, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 1),
+ EPSILON);
- ASSERT_EQ(RAW_Y_OFFSET + 11 * RAW_Y_SCALE, event->getHistoricalRawY(0, 0));
- ASSERT_EQ(RAW_Y_OFFSET + 21 * RAW_Y_SCALE, event->getHistoricalRawY(1, 0));
- ASSERT_EQ(RAW_Y_OFFSET + 111 * RAW_Y_SCALE, event->getHistoricalRawY(0, 1));
- ASSERT_EQ(RAW_Y_OFFSET + 121 * RAW_Y_SCALE, event->getHistoricalRawY(1, 1));
- ASSERT_EQ(RAW_Y_OFFSET + 211 * RAW_Y_SCALE, event->getRawY(0));
- ASSERT_EQ(RAW_Y_OFFSET + 221 * RAW_Y_SCALE, event->getRawY(1));
+ ASSERT_NEAR(RAW_X_OFFSET + 10 * RAW_X_SCALE, event->getHistoricalRawX(0, 0), EPSILON);
+ ASSERT_NEAR(RAW_X_OFFSET + 20 * RAW_X_SCALE, event->getHistoricalRawX(1, 0), EPSILON);
+ ASSERT_NEAR(RAW_X_OFFSET + 110 * RAW_X_SCALE, event->getHistoricalRawX(0, 1), EPSILON);
+ ASSERT_NEAR(RAW_X_OFFSET + 120 * RAW_X_SCALE, event->getHistoricalRawX(1, 1), EPSILON);
+ ASSERT_NEAR(RAW_X_OFFSET + 210 * RAW_X_SCALE, event->getRawX(0), EPSILON);
+ ASSERT_NEAR(RAW_X_OFFSET + 220 * RAW_X_SCALE, event->getRawX(1), EPSILON);
- ASSERT_EQ(X_OFFSET + 10 * X_SCALE, event->getHistoricalX(0, 0));
- ASSERT_EQ(X_OFFSET + 20 * X_SCALE, event->getHistoricalX(1, 0));
- ASSERT_EQ(X_OFFSET + 110 * X_SCALE, event->getHistoricalX(0, 1));
- ASSERT_EQ(X_OFFSET + 120 * X_SCALE, event->getHistoricalX(1, 1));
- ASSERT_EQ(X_OFFSET + 210 * X_SCALE, event->getX(0));
- ASSERT_EQ(X_OFFSET + 220 * X_SCALE, event->getX(1));
+ ASSERT_NEAR(RAW_Y_OFFSET + 11 * RAW_Y_SCALE, event->getHistoricalRawY(0, 0), EPSILON);
+ ASSERT_NEAR(RAW_Y_OFFSET + 21 * RAW_Y_SCALE, event->getHistoricalRawY(1, 0), EPSILON);
+ ASSERT_NEAR(RAW_Y_OFFSET + 111 * RAW_Y_SCALE, event->getHistoricalRawY(0, 1), EPSILON);
+ ASSERT_NEAR(RAW_Y_OFFSET + 121 * RAW_Y_SCALE, event->getHistoricalRawY(1, 1), EPSILON);
+ ASSERT_NEAR(RAW_Y_OFFSET + 211 * RAW_Y_SCALE, event->getRawY(0), EPSILON);
+ ASSERT_NEAR(RAW_Y_OFFSET + 221 * RAW_Y_SCALE, event->getRawY(1), EPSILON);
- ASSERT_EQ(Y_OFFSET + 11 * Y_SCALE, event->getHistoricalY(0, 0));
- ASSERT_EQ(Y_OFFSET + 21 * Y_SCALE, event->getHistoricalY(1, 0));
- ASSERT_EQ(Y_OFFSET + 111 * Y_SCALE, event->getHistoricalY(0, 1));
- ASSERT_EQ(Y_OFFSET + 121 * Y_SCALE, event->getHistoricalY(1, 1));
- ASSERT_EQ(Y_OFFSET + 211 * Y_SCALE, event->getY(0));
- ASSERT_EQ(Y_OFFSET + 221 * Y_SCALE, event->getY(1));
+ ASSERT_NEAR(X_OFFSET + 10 * X_SCALE, event->getHistoricalX(0, 0), EPSILON);
+ ASSERT_NEAR(X_OFFSET + 20 * X_SCALE, event->getHistoricalX(1, 0), EPSILON);
+ ASSERT_NEAR(X_OFFSET + 110 * X_SCALE, event->getHistoricalX(0, 1), EPSILON);
+ ASSERT_NEAR(X_OFFSET + 120 * X_SCALE, event->getHistoricalX(1, 1), EPSILON);
+ ASSERT_NEAR(X_OFFSET + 210 * X_SCALE, event->getX(0), EPSILON);
+ ASSERT_NEAR(X_OFFSET + 220 * X_SCALE, event->getX(1), EPSILON);
+
+ ASSERT_NEAR(Y_OFFSET + 11 * Y_SCALE, event->getHistoricalY(0, 0), EPSILON);
+ ASSERT_NEAR(Y_OFFSET + 21 * Y_SCALE, event->getHistoricalY(1, 0), EPSILON);
+ ASSERT_NEAR(Y_OFFSET + 111 * Y_SCALE, event->getHistoricalY(0, 1), EPSILON);
+ ASSERT_NEAR(Y_OFFSET + 121 * Y_SCALE, event->getHistoricalY(1, 1), EPSILON);
+ ASSERT_NEAR(Y_OFFSET + 211 * Y_SCALE, event->getY(0), EPSILON);
+ ASSERT_NEAR(Y_OFFSET + 221 * Y_SCALE, event->getY(1), EPSILON);
ASSERT_EQ(12, event->getHistoricalPressure(0, 0));
ASSERT_EQ(22, event->getHistoricalPressure(1, 0));
@@ -507,7 +531,7 @@
initializeEventWithHistory(&event);
MotionEvent copy;
- copy.copyFrom(&event, true /*keepHistory*/);
+ copy.copyFrom(&event, /*keepHistory=*/true);
ASSERT_NO_FATAL_FAILURE(assertEqualsEventWithHistory(&event));
}
@@ -517,7 +541,7 @@
initializeEventWithHistory(&event);
MotionEvent copy;
- copy.copyFrom(&event, false /*keepHistory*/);
+ copy.copyFrom(&event, /*keepHistory=*/false);
ASSERT_EQ(event.getPointerCount(), copy.getPointerCount());
ASSERT_EQ(0U, copy.getHistorySize());
@@ -550,10 +574,10 @@
ASSERT_EQ(X_OFFSET * 2, event.getXOffset());
ASSERT_EQ(Y_OFFSET * 2, event.getYOffset());
- ASSERT_EQ((RAW_X_OFFSET + 210 * RAW_X_SCALE) * 2, event.getRawX(0));
- ASSERT_EQ((RAW_Y_OFFSET + 211 * RAW_Y_SCALE) * 2, event.getRawY(0));
- ASSERT_EQ((X_OFFSET + 210 * X_SCALE) * 2, event.getX(0));
- ASSERT_EQ((Y_OFFSET + 211 * Y_SCALE) * 2, event.getY(0));
+ ASSERT_NEAR((RAW_X_OFFSET + 210 * RAW_X_SCALE) * 2, event.getRawX(0), EPSILON);
+ ASSERT_NEAR((RAW_Y_OFFSET + 211 * RAW_Y_SCALE) * 2, event.getRawY(0), EPSILON);
+ ASSERT_NEAR((X_OFFSET + 210 * X_SCALE) * 2, event.getX(0), EPSILON);
+ ASSERT_NEAR((Y_OFFSET + 211 * Y_SCALE) * 2, event.getY(0), EPSILON);
ASSERT_EQ(212, event.getPressure(0));
ASSERT_EQ(213, event.getSize(0));
ASSERT_EQ(214 * 2, event.getTouchMajor(0));
@@ -618,12 +642,12 @@
}
MotionEvent event;
ui::Transform identityTransform;
- event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
- INVALID_HMAC, AMOTION_EVENT_ACTION_MOVE, 0 /*actionButton*/, 0 /*flags*/,
- AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/,
- MotionClassification::NONE, identityTransform, 0 /*xPrecision*/,
- 0 /*yPrecision*/, 3 + RADIUS /*xCursorPosition*/, 2 /*yCursorPosition*/,
- identityTransform, 0 /*downTime*/, 0 /*eventTime*/, pointerCount,
+ event.initialize(InputEvent::nextId(), /*deviceId=*/0, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
+ INVALID_HMAC, AMOTION_EVENT_ACTION_MOVE, /*actionButton=*/0, /*flags=*/0,
+ AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, /*buttonState=*/0,
+ MotionClassification::NONE, identityTransform, /*xPrecision=*/0,
+ /*yPrecision=*/0, /*xCursorPosition=*/3 + RADIUS, /*yCursorPosition=*/2,
+ identityTransform, /*downTime=*/0, /*eventTime=*/0, pointerCount,
pointerProperties, pointerCoords);
float originalRawX = 0 + 3;
float originalRawY = -RADIUS + 2;
@@ -791,18 +815,18 @@
// The x and y axes should have the window transform applied.
const auto newPoint = transform.transform(60, 100);
- ASSERT_EQ(newPoint.x, event.getX(0));
- ASSERT_EQ(newPoint.y, event.getY(0));
+ ASSERT_NEAR(newPoint.x, event.getX(0), EPSILON);
+ ASSERT_NEAR(newPoint.y, event.getY(0), EPSILON);
// The raw values should have the display transform applied.
const auto raw = rawTransform.transform(60, 100);
- ASSERT_EQ(raw.x, event.getRawX(0));
- ASSERT_EQ(raw.y, event.getRawY(0));
+ ASSERT_NEAR(raw.x, event.getRawX(0), EPSILON);
+ ASSERT_NEAR(raw.y, event.getRawY(0), EPSILON);
// Relative values should have the window transform applied without any translation.
const auto rel = transformWithoutTranslation(transform, 42, 96);
- ASSERT_EQ(rel.x, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0));
- ASSERT_EQ(rel.y, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0));
+ ASSERT_NEAR(rel.x, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0), EPSILON);
+ ASSERT_NEAR(rel.y, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0), EPSILON);
}
TEST_F(MotionEventTest, Initialize_SetsClassification) {
@@ -824,12 +848,12 @@
ui::Transform identityTransform;
for (MotionClassification classification : classifications) {
- event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN,
+ event.initialize(InputEvent::nextId(), /*deviceId=*/0, AINPUT_SOURCE_TOUCHSCREEN,
DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0,
AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, classification,
identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, 0 /*downTime*/,
- 0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords);
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, /*downTime=*/0,
+ /*eventTime=*/0, pointerCount, pointerProperties, pointerCoords);
ASSERT_EQ(classification, event.getClassification());
}
}
@@ -846,11 +870,11 @@
}
ui::Transform identityTransform;
- event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_MOUSE, DISPLAY_ID,
+ event.initialize(InputEvent::nextId(), /*deviceId=*/0, AINPUT_SOURCE_MOUSE, DISPLAY_ID,
INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE,
AMETA_NONE, 0, MotionClassification::NONE, identityTransform, 0, 0,
- 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, identityTransform,
- 0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties,
+ /*xCursorPosition=*/280, /*yCursorPosition=*/540, identityTransform,
+ /*downTime=*/0, /*eventTime=*/0, pointerCount, pointerProperties,
pointerCoords);
event.offsetLocation(20, 60);
ASSERT_EQ(280, event.getRawXCursorPosition());
@@ -869,4 +893,42 @@
ASSERT_EQ(4, event.getYCursorPosition());
}
+TEST_F(MotionEventTest, CoordinatesAreRoundedAppropriately) {
+ // These are specifically integral values, since we are testing for rounding.
+ const vec2 EXPECTED{400.f, 700.f};
+
+ // Pick a transform such that transforming the point with its inverse and bringing that
+ // back to the original coordinate space results in a non-zero error amount due to the
+ // nature of floating point arithmetics. This can happen when the display is scaled.
+ // For example, the 'adb shell wm size' command can be used to set an override for the
+ // logical display size, which could result in the display being scaled.
+ constexpr float scale = 720.f / 1080.f;
+ ui::Transform transform;
+ transform.set(scale, 0, 0, scale);
+ ASSERT_NE(EXPECTED, transform.transform(transform.inverse().transform(EXPECTED)));
+
+ // Store the inverse-transformed values in the motion event.
+ const vec2 rawCoords = transform.inverse().transform(EXPECTED);
+ PointerCoords pc{};
+ pc.setAxisValue(AMOTION_EVENT_AXIS_X, rawCoords.x);
+ pc.setAxisValue(AMOTION_EVENT_AXIS_Y, rawCoords.y);
+ PointerProperties pp{};
+ MotionEvent event;
+ event.initialize(InputEvent::nextId(), 2, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, HMAC,
+ AMOTION_EVENT_ACTION_MOVE, 0, AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED,
+ AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY,
+ MotionClassification::NONE, transform, 2.0f, 2.1f, rawCoords.x, rawCoords.y,
+ transform, ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME, 1, &pp, &pc);
+
+ // When using the getters from the MotionEvent to obtain the coordinates, the transformed
+ // values should be rounded by an appropriate amount so that they now precisely equal the
+ // original coordinates.
+ ASSERT_EQ(EXPECTED.x, event.getX(0));
+ ASSERT_EQ(EXPECTED.y, event.getY(0));
+ ASSERT_EQ(EXPECTED.x, event.getRawX(0));
+ ASSERT_EQ(EXPECTED.y, event.getRawY(0));
+ ASSERT_EQ(EXPECTED.x, event.getXCursorPosition());
+ ASSERT_EQ(EXPECTED.y, event.getYCursorPosition());
+}
+
} // namespace android
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index 70e4fda..5d8b970 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -25,6 +25,8 @@
namespace android {
+constexpr static float EPSILON = MotionEvent::ROUNDING_PRECISION;
+
class InputPublisherAndConsumerTest : public testing::Test {
protected:
std::shared_ptr<InputChannel> mServerChannel, mClientChannel;
@@ -90,7 +92,7 @@
uint32_t consumeSeq;
InputEvent* event;
- status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
+ status = mConsumer->consume(&mEventFactory, /*consumeBatches=*/true, -1, &consumeSeq, &event);
ASSERT_EQ(OK, status)
<< "consumer consume should return OK";
@@ -199,7 +201,7 @@
uint32_t consumeSeq;
InputEvent* event;
- status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
+ status = mConsumer->consume(&mEventFactory, /*consumeBatches=*/true, -1, &consumeSeq, &event);
ASSERT_EQ(OK, status)
<< "consumer consume should return OK";
@@ -226,10 +228,10 @@
EXPECT_EQ(yOffset, motionEvent->getYOffset());
EXPECT_EQ(xPrecision, motionEvent->getXPrecision());
EXPECT_EQ(yPrecision, motionEvent->getYPrecision());
- EXPECT_EQ(xCursorPosition, motionEvent->getRawXCursorPosition());
- EXPECT_EQ(yCursorPosition, motionEvent->getRawYCursorPosition());
- EXPECT_EQ(xCursorPosition * xScale + xOffset, motionEvent->getXCursorPosition());
- EXPECT_EQ(yCursorPosition * yScale + yOffset, motionEvent->getYCursorPosition());
+ EXPECT_NEAR(xCursorPosition, motionEvent->getRawXCursorPosition(), EPSILON);
+ EXPECT_NEAR(yCursorPosition, motionEvent->getRawYCursorPosition(), EPSILON);
+ EXPECT_NEAR(xCursorPosition * xScale + xOffset, motionEvent->getXCursorPosition(), EPSILON);
+ EXPECT_NEAR(yCursorPosition * yScale + yOffset, motionEvent->getYCursorPosition(), EPSILON);
EXPECT_EQ(rawTransform, motionEvent->getRawTransform());
EXPECT_EQ(downTime, motionEvent->getDownTime());
EXPECT_EQ(eventTime, motionEvent->getEventTime());
@@ -242,10 +244,12 @@
EXPECT_EQ(pointerProperties[i].toolType, motionEvent->getToolType(i));
const auto& pc = pointerCoords[i];
- EXPECT_EQ(pc.getX() * rawXScale + rawXOffset, motionEvent->getRawX(i));
- EXPECT_EQ(pc.getY() * rawYScale + rawYOffset, motionEvent->getRawY(i));
- EXPECT_EQ(pc.getX() * xScale + xOffset, motionEvent->getX(i));
- EXPECT_EQ(pc.getY() * yScale + yOffset, motionEvent->getY(i));
+ EXPECT_EQ(pc, motionEvent->getSamplePointerCoords()[i]);
+
+ EXPECT_NEAR(pc.getX() * rawXScale + rawXOffset, motionEvent->getRawX(i), EPSILON);
+ EXPECT_NEAR(pc.getY() * rawYScale + rawYOffset, motionEvent->getRawY(i), EPSILON);
+ EXPECT_NEAR(pc.getX() * xScale + xOffset, motionEvent->getX(i), EPSILON);
+ EXPECT_NEAR(pc.getY() * yScale + yOffset, motionEvent->getY(i), EPSILON);
EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), motionEvent->getPressure(i));
EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_SIZE), motionEvent->getSize(i));
EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), motionEvent->getTouchMajor(i));
@@ -290,7 +294,7 @@
uint32_t consumeSeq;
InputEvent* event;
- status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
+ status = mConsumer->consume(&mEventFactory, /*consumeBatches=*/true, -1, &consumeSeq, &event);
ASSERT_EQ(OK, status) << "consumer consume should return OK";
ASSERT_TRUE(event != nullptr) << "consumer should have returned non-NULL event";
@@ -331,7 +335,7 @@
uint32_t consumeSeq;
InputEvent* event;
- status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
+ status = mConsumer->consume(&mEventFactory, /*consumeBatches=*/true, -1, &consumeSeq, &event);
ASSERT_EQ(OK, status) << "consumer consume should return OK";
ASSERT_TRUE(event != nullptr) << "consumer should have returned non-NULL event";
@@ -373,7 +377,7 @@
uint32_t consumeSeq;
InputEvent* event;
- status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
+ status = mConsumer->consume(&mEventFactory, /*consumeBatches=*/true, -1, &consumeSeq, &event);
ASSERT_EQ(OK, status) << "consumer consume should return OK";
ASSERT_TRUE(event != nullptr) << "consumer should have returned non-NULL event";
@@ -415,7 +419,7 @@
uint32_t consumeSeq;
InputEvent* event;
- status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
+ status = mConsumer->consume(&mEventFactory, /*consumeBatches=*/true, -1, &consumeSeq, &event);
ASSERT_EQ(OK, status) << "consumer consume should return OK";
ASSERT_TRUE(event != nullptr) << "consumer should have returned non-NULL event";
diff --git a/libs/input/tests/TouchResampling_test.cpp b/libs/input/tests/TouchResampling_test.cpp
index d01258c..7cb9526 100644
--- a/libs/input/tests/TouchResampling_test.cpp
+++ b/libs/input/tests/TouchResampling_test.cpp
@@ -56,7 +56,7 @@
mPublisher = std::make_unique<InputPublisher>(std::move(serverChannel));
mConsumer = std::make_unique<InputConsumer>(std::move(clientChannel),
- true /* enableTouchResampling */);
+ /*enableTouchResampling=*/true);
}
status_t publishSimpleMotionEventWithCoords(int32_t action, nsecs_t eventTime,
@@ -79,11 +79,11 @@
if (action == AMOTION_EVENT_ACTION_DOWN && eventTime != 0) {
ADD_FAILURE() << "Downtime should be equal to 0 (hardcoded for convenience)";
}
- return mPublisher->publishMotionEvent(mSeq++, InputEvent::nextId(), 1 /*deviceId*/,
- AINPUT_SOURCE_TOUCHSCREEN, 0 /*displayId*/, INVALID_HMAC,
- action, 0 /*actionButton*/, 0 /*flags*/, 0 /*edgeFlags*/,
- AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE,
- identityTransform, 0 /*xPrecision*/, 0 /*yPrecision*/,
+ return mPublisher->publishMotionEvent(mSeq++, InputEvent::nextId(), /*deviceId=*/1,
+ AINPUT_SOURCE_TOUCHSCREEN, /*displayId=*/0, INVALID_HMAC,
+ action, /*actionButton=*/0, /*flags=*/0, /*edgeFlags=*/0,
+ AMETA_NONE, /*buttonState=*/0, MotionClassification::NONE,
+ identityTransform, /*xPrecision=*/0, /*yPrecision=*/0,
AMOTION_EVENT_INVALID_CURSOR_POSITION,
AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform,
downTime, eventTime, properties.size(), properties.data(),
@@ -161,7 +161,7 @@
uint32_t consumeSeq;
InputEvent* event;
- status_t status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, frameTime.count(),
+ status_t status = mConsumer->consume(&mEventFactory, /*consumeBatches=*/true, frameTime.count(),
&consumeSeq, &event);
ASSERT_EQ(OK, status);
MotionEvent* motionEvent = static_cast<MotionEvent*>(event);
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index c6ad3a2..0277579 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -159,13 +159,13 @@
MotionEvent event;
ui::Transform identityTransform;
- event.initialize(InputEvent::nextId(), 5 /*deviceId*/, AINPUT_SOURCE_ROTARY_ENCODER,
+ event.initialize(InputEvent::nextId(), /*deviceId=*/5, AINPUT_SOURCE_ROTARY_ENCODER,
ADISPLAY_ID_NONE, INVALID_HMAC, AMOTION_EVENT_ACTION_SCROLL,
- 0 /*actionButton*/, 0 /*flags*/, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE,
- 0 /*buttonState*/, MotionClassification::NONE, identityTransform,
- 0 /*xPrecision*/, 0 /*yPrecision*/, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, 0 /*downTime*/,
- timeStamp.count(), 1 /*pointerCount*/, properties, coords);
+ /*actionButton=*/0, /*flags=*/0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE,
+ /*buttonState=*/0, MotionClassification::NONE, identityTransform,
+ /*xPrecision=*/0, /*yPrecision=*/0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, /*downTime=*/0,
+ timeStamp.count(), /*pointerCount=*/1, properties, coords);
events.emplace_back(event);
}
@@ -219,12 +219,12 @@
MotionEvent event;
ui::Transform identityTransform;
- event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN,
- DISPLAY_ID, INVALID_HMAC, action, 0 /*actionButton*/, 0 /*flags*/,
- AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/,
- MotionClassification::NONE, identityTransform, 0 /*xPrecision*/,
- 0 /*yPrecision*/, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, 0 /*downTime*/,
+ event.initialize(InputEvent::nextId(), /*deviceId=*/0, AINPUT_SOURCE_TOUCHSCREEN,
+ DISPLAY_ID, INVALID_HMAC, action, /*actionButton=*/0, /*flags=*/0,
+ AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, /*buttonState=*/0,
+ MotionClassification::NONE, identityTransform, /*xPrecision=*/0,
+ /*yPrecision=*/0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, /*downTime=*/0,
entry.eventTime.count(), pointerCount, properties, coords);
events.emplace_back(event);
@@ -341,23 +341,23 @@
TEST_F(VelocityTrackerTest, TestComputedVelocity) {
VelocityTracker::ComputedVelocity computedVelocity;
- computedVelocity.addVelocity(AMOTION_EVENT_AXIS_X, 0 /*id*/, 200 /*velocity*/);
- computedVelocity.addVelocity(AMOTION_EVENT_AXIS_X, 26U /*id*/, 400 /*velocity*/);
- computedVelocity.addVelocity(AMOTION_EVENT_AXIS_X, 27U /*id*/, 650 /*velocity*/);
- computedVelocity.addVelocity(AMOTION_EVENT_AXIS_X, MAX_POINTER_ID, 750 /*velocity*/);
- computedVelocity.addVelocity(AMOTION_EVENT_AXIS_Y, 0 /*id*/, 1000 /*velocity*/);
- computedVelocity.addVelocity(AMOTION_EVENT_AXIS_Y, 26U /*id*/, 2000 /*velocity*/);
- computedVelocity.addVelocity(AMOTION_EVENT_AXIS_Y, 27U /*id*/, 3000 /*velocity*/);
- computedVelocity.addVelocity(AMOTION_EVENT_AXIS_Y, MAX_POINTER_ID, 4000 /*velocity*/);
+ computedVelocity.addVelocity(AMOTION_EVENT_AXIS_X, /*id=*/0, /*velocity=*/200);
+ computedVelocity.addVelocity(AMOTION_EVENT_AXIS_X, /*id=*/26U, /*velocity=*/400);
+ computedVelocity.addVelocity(AMOTION_EVENT_AXIS_X, /*id=*/27U, /*velocity=*/650);
+ computedVelocity.addVelocity(AMOTION_EVENT_AXIS_X, MAX_POINTER_ID, /*velocity=*/750);
+ computedVelocity.addVelocity(AMOTION_EVENT_AXIS_Y, /*id=*/0, /*velocity=*/1000);
+ computedVelocity.addVelocity(AMOTION_EVENT_AXIS_Y, /*id=*/26U, /*velocity=*/2000);
+ computedVelocity.addVelocity(AMOTION_EVENT_AXIS_Y, /*id=*/27U, /*velocity=*/3000);
+ computedVelocity.addVelocity(AMOTION_EVENT_AXIS_Y, MAX_POINTER_ID, /*velocity=*/4000);
// Check the axes/indices with velocity.
- EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, 0U /*id*/)), 200);
- EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, 26U /*id*/)), 400);
- EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, 27U /*id*/)), 650);
+ EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, /*id=*/0U)), 200);
+ EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, /*id=*/26U)), 400);
+ EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, /*id=*/27U)), 650);
EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, MAX_POINTER_ID)), 750);
- EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, 0U /*id*/)), 1000);
- EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, 26U /*id*/)), 2000);
- EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, 27U /*id*/)), 3000);
+ EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, /*id=*/0U)), 1000);
+ EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, /*id=*/26U)), 2000);
+ EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, /*id=*/27U)), 3000);
EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, MAX_POINTER_ID)), 4000);
for (uint32_t id = 0; id <= MAX_POINTER_ID; id++) {
// Since no data was added for AXIS_SCROLL, expect empty value for the axis for any id.
@@ -436,17 +436,17 @@
float maxFloat = std::numeric_limits<float>::max();
VelocityTracker::ComputedVelocity computedVelocity;
- computedVelocity = vt.getComputedVelocity(1000 /* units */, maxFloat);
+ computedVelocity = vt.getComputedVelocity(/*units=*/1000, maxFloat);
checkVelocity(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, DEFAULT_POINTER_ID)),
764.345703);
// Expect X velocity to be scaled with respective to provided units.
- computedVelocity = vt.getComputedVelocity(1000000 /* units */, maxFloat);
+ computedVelocity = vt.getComputedVelocity(/*units=*/1000000, maxFloat);
checkVelocity(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, DEFAULT_POINTER_ID)),
764345.703);
// Expect X velocity to be clamped by provided max velocity.
- computedVelocity = vt.getComputedVelocity(1000000 /* units */, 1000);
+ computedVelocity = vt.getComputedVelocity(/*units=*/1000000, 1000);
checkVelocity(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, DEFAULT_POINTER_ID)), 1000);
// All 0 data for Y; expect 0 velocity.
diff --git a/libs/input/tests/VerifiedInputEvent_test.cpp b/libs/input/tests/VerifiedInputEvent_test.cpp
index f2b59ea..277d74d 100644
--- a/libs/input/tests/VerifiedInputEvent_test.cpp
+++ b/libs/input/tests/VerifiedInputEvent_test.cpp
@@ -23,10 +23,10 @@
static KeyEvent getKeyEventWithFlags(int32_t flags) {
KeyEvent event;
- event.initialize(InputEvent::nextId(), 2 /*deviceId*/, AINPUT_SOURCE_GAMEPAD,
+ event.initialize(InputEvent::nextId(), /*deviceId=*/2, AINPUT_SOURCE_GAMEPAD,
ADISPLAY_ID_DEFAULT, INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, flags,
- AKEYCODE_BUTTON_X, 121 /*scanCode*/, AMETA_ALT_ON, 1 /*repeatCount*/,
- 1000 /*downTime*/, 2000 /*eventTime*/);
+ AKEYCODE_BUTTON_X, /*scanCode=*/121, AMETA_ALT_ON, /*repeatCount=*/1,
+ /*downTime=*/1000, /*eventTime=*/2000);
return event;
}
@@ -44,12 +44,12 @@
ui::Transform transform;
transform.set({2, 0, 4, 0, 3, 5, 0, 0, 1});
ui::Transform identity;
- event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_DEFAULT,
- INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/, flags,
- AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/,
- MotionClassification::NONE, transform, 0.1 /*xPrecision*/, 0.2 /*yPrecision*/,
- 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, identity, 100 /*downTime*/,
- 200 /*eventTime*/, pointerCount, pointerProperties, pointerCoords);
+ event.initialize(InputEvent::nextId(), /*deviceId=*/0, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_DEFAULT,
+ INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, /*actionButton=*/0, flags,
+ AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, /*buttonState=*/0,
+ MotionClassification::NONE, transform, /*xPrecision=*/0.1, /*yPrecision=*/0.2,
+ /*xCursorPosition=*/280, /*yCursorPosition=*/540, identity, /*downTime=*/100,
+ /*eventTime=*/200, pointerCount, pointerProperties, pointerCoords);
return event;
}
diff --git a/libs/jpegrecoverymap/include/jpegrecoverymap/jpegr.h b/libs/jpegrecoverymap/include/jpegrecoverymap/jpegr.h
index a433e8a..e2023a6 100644
--- a/libs/jpegrecoverymap/include/jpegrecoverymap/jpegr.h
+++ b/libs/jpegrecoverymap/include/jpegrecoverymap/jpegr.h
@@ -91,7 +91,10 @@
int length;
};
-struct jpegr_metadata {
+/*
+ * Holds information for recovery map related metadata.
+ */
+struct jpegr_metadata_struct {
// JPEG/R version
uint32_t version;
// Max Content Boost for the map
@@ -103,12 +106,14 @@
typedef struct jpegr_uncompressed_struct* jr_uncompressed_ptr;
typedef struct jpegr_compressed_struct* jr_compressed_ptr;
typedef struct jpegr_exif_struct* jr_exif_ptr;
-typedef struct jpegr_metadata* jr_metadata_ptr;
+typedef struct jpegr_metadata_struct* jr_metadata_ptr;
typedef struct jpegr_info_struct* jr_info_ptr;
class JpegR {
public:
/*
+ * Experimental only
+ *
* Encode API-0
* Compress JPEGR image from 10-bit HDR YUV.
*
@@ -199,19 +204,40 @@
* Decode API
* Decompress JPEGR image.
*
- * The output JPEGR image is in RGBA_1010102 data format if decoding to HDR.
- * @param compressed_jpegr_image compressed JPEGR image
- * @param dest destination of the uncompressed JPEGR image
- * @param exif destination of the decoded EXIF metadata.
- * @param output_format flag for setting output color format. if set to
- * {@code JPEGR_OUTPUT_SDR}, decoder will only decode the primary image
- * which is SDR. Default value is JPEGR_OUTPUT_HDR_LINEAR.
+ * @param compressed_jpegr_image compressed JPEGR image.
+ * @param dest destination of the uncompressed JPEGR image.
+ * @param exif destination of the decoded EXIF metadata. The default value is NULL where the
+ decoder will do nothing about it. If configured not NULL the decoder will write
+ EXIF data into this structure. The format is defined in {@code jpegr_exif_struct}
+ * @param output_format flag for setting output color format. Its value configures the output
+ color format. The default value is {@code JPEGR_OUTPUT_HDR_LINEAR}.
+ ----------------------------------------------------------------------
+ | output_format | decoded color format to be written |
+ ----------------------------------------------------------------------
+ | JPEGR_OUTPUT_SDR | RGBA_8888 |
+ ----------------------------------------------------------------------
+ | JPEGR_OUTPUT_HDR_LINEAR | (default)RGBA_F16 linear |
+ ----------------------------------------------------------------------
+ | JPEGR_OUTPUT_HDR_PQ | RGBA_1010102 PQ |
+ ----------------------------------------------------------------------
+ | JPEGR_OUTPUT_HDR_HLG | RGBA_1010102 HLG |
+ ----------------------------------------------------------------------
+ * @param recovery_map destination of the decoded recovery map. The default value is NULL where
+ the decoder will do nothing about it. If configured not NULL the decoder
+ will write the decoded recovery_map data into this structure. The format
+ is defined in {@code jpegr_uncompressed_struct}.
+ * @param metadata destination of the decoded metadata. The default value is NULL where the
+ decoder will do nothing about it. If configured not NULL the decoder will
+ write metadata into this structure. the format of metadata is defined in
+ {@code jpegr_metadata}.
* @return NO_ERROR if decoding succeeds, error code if error occurs.
*/
status_t decodeJPEGR(jr_compressed_ptr compressed_jpegr_image,
jr_uncompressed_ptr dest,
jr_exif_ptr exif = nullptr,
- jpegr_output_format output_format = JPEGR_OUTPUT_HDR_LINEAR);
+ jpegr_output_format output_format = JPEGR_OUTPUT_HDR_LINEAR,
+ jr_uncompressed_ptr recovery_map = nullptr,
+ jr_metadata_ptr metadata = nullptr);
/*
* Gets Info from JPEGR file without decoding it.
diff --git a/libs/jpegrecoverymap/include/jpegrecoverymap/jpegrutils.h b/libs/jpegrecoverymap/include/jpegrecoverymap/jpegrutils.h
index a381743..dd06fa2 100644
--- a/libs/jpegrecoverymap/include/jpegrecoverymap/jpegrutils.h
+++ b/libs/jpegrecoverymap/include/jpegrecoverymap/jpegrutils.h
@@ -45,7 +45,7 @@
#define Endian_SwapBE16(n) (n)
#endif
-struct jpegr_metadata;
+struct jpegr_metadata_struct;
/*
* Mutable data structure. Holds information for metadata.
*/
@@ -87,7 +87,7 @@
* @param metadata place to store HDR metadata values
* @return true if metadata is successfully retrieved, false otherwise
*/
-bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, jpegr_metadata* metadata);
+bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, jpegr_metadata_struct* metadata);
/*
* This method generates XMP metadata for the primary image.
@@ -156,7 +156,7 @@
* @param metadata JPEG/R metadata to encode as XMP
* @return XMP metadata in type of string
*/
- std::string generateXmpForSecondaryImage(jpegr_metadata& metadata);
+ std::string generateXmpForSecondaryImage(jpegr_metadata_struct& metadata);
} // namespace android::jpegrecoverymap
#endif //ANDROID_JPEGRECOVERYMAP_JPEGRUTILS_H
diff --git a/libs/jpegrecoverymap/jpegr.cpp b/libs/jpegrecoverymap/jpegr.cpp
index b115750..e197bf0 100644
--- a/libs/jpegrecoverymap/jpegr.cpp
+++ b/libs/jpegrecoverymap/jpegr.cpp
@@ -107,7 +107,7 @@
return ERROR_JPEGR_INVALID_INPUT_TYPE;
}
- jpegr_metadata metadata;
+ jpegr_metadata_struct metadata;
metadata.version = kJpegrVersion;
jpegr_uncompressed_struct uncompressed_yuv_420_image;
@@ -176,7 +176,7 @@
return ERROR_JPEGR_INVALID_INPUT_TYPE;
}
- jpegr_metadata metadata;
+ jpegr_metadata_struct metadata;
metadata.version = kJpegrVersion;
jpegr_uncompressed_struct map;
@@ -235,7 +235,7 @@
return ERROR_JPEGR_INVALID_INPUT_TYPE;
}
- jpegr_metadata metadata;
+ jpegr_metadata_struct metadata;
metadata.version = kJpegrVersion;
jpegr_uncompressed_struct map;
@@ -288,7 +288,7 @@
return ERROR_JPEGR_RESOLUTION_MISMATCH;
}
- jpegr_metadata metadata;
+ jpegr_metadata_struct metadata;
metadata.version = kJpegrVersion;
jpegr_uncompressed_struct map;
@@ -331,7 +331,9 @@
status_t JpegR::decodeJPEGR(jr_compressed_ptr compressed_jpegr_image,
jr_uncompressed_ptr dest,
jr_exif_ptr exif,
- jpegr_output_format output_format) {
+ jpegr_output_format output_format,
+ jr_uncompressed_ptr recovery_map,
+ jr_metadata_ptr metadata) {
if (compressed_jpegr_image == nullptr || dest == nullptr) {
return ERROR_JPEGR_INVALID_NULL_PTR;
}
@@ -350,13 +352,58 @@
uncompressed_rgba_image.width * uncompressed_rgba_image.height * 4);
dest->width = uncompressed_rgba_image.width;
dest->height = uncompressed_rgba_image.height;
- return NO_ERROR;
+
+ if (recovery_map == nullptr && exif == nullptr) {
+ return NO_ERROR;
+ }
+
+ if (exif != nullptr) {
+ if (exif->data == nullptr) {
+ return ERROR_JPEGR_INVALID_NULL_PTR;
+ }
+ if (exif->length < jpeg_decoder.getEXIFSize()) {
+ return ERROR_JPEGR_BUFFER_TOO_SMALL;
+ }
+ memcpy(exif->data, jpeg_decoder.getEXIFPtr(), jpeg_decoder.getEXIFSize());
+ exif->length = jpeg_decoder.getEXIFSize();
+ }
+ if (recovery_map == nullptr) {
+ return NO_ERROR;
+ }
}
jpegr_compressed_struct compressed_map;
- jpegr_metadata metadata;
JPEGR_CHECK(extractRecoveryMap(compressed_jpegr_image, &compressed_map));
+ JpegDecoderHelper recovery_map_decoder;
+ if (!recovery_map_decoder.decompressImage(compressed_map.data, compressed_map.length)) {
+ return ERROR_JPEGR_DECODE_ERROR;
+ }
+
+ if (recovery_map != nullptr) {
+ recovery_map->width = recovery_map_decoder.getDecompressedImageWidth();
+ recovery_map->height = recovery_map_decoder.getDecompressedImageHeight();
+ int size = recovery_map->width * recovery_map->height;
+ recovery_map->data = malloc(size);
+ memcpy(recovery_map->data, recovery_map_decoder.getDecompressedImagePtr(), size);
+ }
+
+ jpegr_metadata_struct jr_metadata;
+ if (!getMetadataFromXMP(static_cast<uint8_t*>(recovery_map_decoder.getXMPPtr()),
+ recovery_map_decoder.getXMPSize(), &jr_metadata)) {
+ return ERROR_JPEGR_DECODE_ERROR;
+ }
+
+ if (metadata != nullptr) {
+ metadata->version = jr_metadata.version;
+ metadata->minContentBoost = jr_metadata.minContentBoost;
+ metadata->maxContentBoost = jr_metadata.maxContentBoost;
+ }
+
+ if (output_format == JPEGR_OUTPUT_SDR) {
+ return NO_ERROR;
+ }
+
JpegDecoderHelper jpeg_decoder;
if (!jpeg_decoder.decompressImage(compressed_jpegr_image->data, compressed_jpegr_image->length)) {
return ERROR_JPEGR_DECODE_ERROR;
@@ -373,11 +420,6 @@
exif->length = jpeg_decoder.getEXIFSize();
}
- JpegDecoderHelper recovery_map_decoder;
- if (!recovery_map_decoder.decompressImage(compressed_map.data, compressed_map.length)) {
- return ERROR_JPEGR_DECODE_ERROR;
- }
-
jpegr_uncompressed_struct map;
map.data = recovery_map_decoder.getDecompressedImagePtr();
map.width = recovery_map_decoder.getDecompressedImageWidth();
@@ -388,12 +430,8 @@
uncompressed_yuv_420_image.width = jpeg_decoder.getDecompressedImageWidth();
uncompressed_yuv_420_image.height = jpeg_decoder.getDecompressedImageHeight();
- if (!getMetadataFromXMP(static_cast<uint8_t*>(recovery_map_decoder.getXMPPtr()),
- recovery_map_decoder.getXMPSize(), &metadata)) {
- return ERROR_JPEGR_DECODE_ERROR;
- }
-
- JPEGR_CHECK(applyRecoveryMap(&uncompressed_yuv_420_image, &map, &metadata, output_format, dest));
+ JPEGR_CHECK(applyRecoveryMap(&uncompressed_yuv_420_image, &map, &jr_metadata, output_format,
+ dest));
return NO_ERROR;
}
diff --git a/libs/jpegrecoverymap/jpegrutils.cpp b/libs/jpegrecoverymap/jpegrutils.cpp
index 38b78ad..ff96447 100644
--- a/libs/jpegrecoverymap/jpegrutils.cpp
+++ b/libs/jpegrecoverymap/jpegrutils.cpp
@@ -253,7 +253,7 @@
const string XMPXmlHandler::minContentBoostAttrName = kMapGainMapMin;
const string XMPXmlHandler::maxContentBoostAttrName = kMapGainMapMax;
-bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, jpegr_metadata* metadata) {
+bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, jpegr_metadata_struct* metadata) {
string nameSpace = "http://ns.adobe.com/xap/1.0/\0";
if (xmp_size < nameSpace.size()+2) {
@@ -327,7 +327,7 @@
return ss.str();
}
-string generateXmpForSecondaryImage(jpegr_metadata& metadata) {
+string generateXmpForSecondaryImage(jpegr_metadata_struct& metadata) {
const vector<string> kConDirSeq({kConDirectory, string("rdf:Seq")});
const vector<string> kLiItem({string("rdf:li"), kConItem});
diff --git a/libs/jpegrecoverymap/tests/jpegr_test.cpp b/libs/jpegrecoverymap/tests/jpegr_test.cpp
index 0a7d20a..be4b972 100644
--- a/libs/jpegrecoverymap/tests/jpegr_test.cpp
+++ b/libs/jpegrecoverymap/tests/jpegr_test.cpp
@@ -174,7 +174,7 @@
}
TEST_F(JpegRTest, writeXmpThenRead) {
- jpegr_metadata metadata_expected;
+ jpegr_metadata_struct metadata_expected;
metadata_expected.maxContentBoost = 1.25;
metadata_expected.minContentBoost = 0.75;
const std::string nameSpace = "http://ns.adobe.com/xap/1.0/\0";
@@ -189,7 +189,7 @@
xmpData.insert(xmpData.end(), reinterpret_cast<const uint8_t*>(xmp.c_str()),
reinterpret_cast<const uint8_t*>(xmp.c_str()) + xmp.size());
- jpegr_metadata metadata_read;
+ jpegr_metadata_struct metadata_read;
EXPECT_TRUE(getMetadataFromXMP(xmpData.data(), xmpData.size(), &metadata_read));
ASSERT_EQ(metadata_expected.maxContentBoost, metadata_read.maxContentBoost);
ASSERT_EQ(metadata_expected.minContentBoost, metadata_read.minContentBoost);
@@ -476,7 +476,7 @@
JpegRBenchmark benchmark;
- jpegr_metadata metadata = { .version = 1,
+ jpegr_metadata_struct metadata = { .version = 1,
.maxContentBoost = 8.0f,
.minContentBoost = 1.0f / 8.0f };
diff --git a/libs/jpegrecoverymap/tests/recoverymapmath_test.cpp b/libs/jpegrecoverymap/tests/recoverymapmath_test.cpp
index 6c61ff1..cf6a034 100644
--- a/libs/jpegrecoverymap/tests/recoverymapmath_test.cpp
+++ b/libs/jpegrecoverymap/tests/recoverymapmath_test.cpp
@@ -554,8 +554,8 @@
TEST_F(RecoveryMapMathTest, applyRecoveryLUT) {
for (int boost = 1; boost <= 10; boost++) {
- jpegr_metadata metadata = { .maxContentBoost = static_cast<float>(boost),
- .minContentBoost = 1.0f / static_cast<float>(boost) };
+ jpegr_metadata_struct metadata = { .maxContentBoost = static_cast<float>(boost),
+ .minContentBoost = 1.0f / static_cast<float>(boost) };
RecoveryLUT recoveryLUT(&metadata);
for (int idx = 0; idx < kRecoveryFactorNumEntries; idx++) {
float value = static_cast<float>(idx) / static_cast<float>(kRecoveryFactorNumEntries - 1);
@@ -573,8 +573,8 @@
}
for (int boost = 1; boost <= 10; boost++) {
- jpegr_metadata metadata = { .maxContentBoost = static_cast<float>(boost),
- .minContentBoost = 1.0f };
+ jpegr_metadata_struct metadata = { .maxContentBoost = static_cast<float>(boost),
+ .minContentBoost = 1.0f };
RecoveryLUT recoveryLUT(&metadata);
for (int idx = 0; idx < kRecoveryFactorNumEntries; idx++) {
float value = static_cast<float>(idx) / static_cast<float>(kRecoveryFactorNumEntries - 1);
@@ -592,8 +592,8 @@
}
for (int boost = 1; boost <= 10; boost++) {
- jpegr_metadata metadata = { .maxContentBoost = static_cast<float>(boost),
- .minContentBoost = 1.0f / pow(static_cast<float>(boost),
+ jpegr_metadata_struct metadata = { .maxContentBoost = static_cast<float>(boost),
+ .minContentBoost = 1.0f / pow(static_cast<float>(boost),
1.0f / 3.0f) };
RecoveryLUT recoveryLUT(&metadata);
for (int idx = 0; idx < kRecoveryFactorNumEntries; idx++) {
@@ -659,8 +659,8 @@
}
TEST_F(RecoveryMapMathTest, EncodeRecovery) {
- jpegr_metadata metadata = { .maxContentBoost = 4.0f,
- .minContentBoost = 1.0f / 4.0f };
+ jpegr_metadata_struct metadata = { .maxContentBoost = 4.0f,
+ .minContentBoost = 1.0f / 4.0f };
EXPECT_EQ(encodeRecovery(0.0f, 0.0f, &metadata), 127);
EXPECT_EQ(encodeRecovery(0.0f, 1.0f, &metadata), 127);
@@ -717,8 +717,8 @@
}
TEST_F(RecoveryMapMathTest, ApplyRecovery) {
- jpegr_metadata metadata = { .maxContentBoost = 4.0f,
- .minContentBoost = 1.0f / 4.0f };
+ jpegr_metadata_struct metadata = { .maxContentBoost = 4.0f,
+ .minContentBoost = 1.0f / 4.0f };
EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), 0.0f, &metadata), RgbBlack());
EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), 0.5f, &metadata), RgbBlack());
@@ -981,8 +981,8 @@
}
TEST_F(RecoveryMapMathTest, ApplyMap) {
- jpegr_metadata metadata = { .maxContentBoost = 8.0f,
- .minContentBoost = 1.0f / 8.0f };
+ jpegr_metadata_struct metadata = { .maxContentBoost = 8.0f,
+ .minContentBoost = 1.0f / 8.0f };
EXPECT_RGB_EQ(Recover(YuvWhite(), 1.0f, &metadata),
RgbWhite() * 8.0f);
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 0b755aa..c2c856e 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -322,6 +322,16 @@
mExtensionString = gBuiltinExtensionString;
+ // b/269060366 Conditionally enabled EGL_ANDROID_get_frame_timestamps extension if the
+ // device's present timestamps are reliable (which may not be the case on emulators).
+ if (cnx->useAngle) {
+ if (android::base::GetBoolProperty("service.sf.present_timestamp", false)) {
+ mExtensionString.append("EGL_ANDROID_get_frame_timestamps");
+ }
+ } else {
+ mExtensionString.append("EGL_ANDROID_get_frame_timestamps");
+ }
+
hasColorSpaceSupport = findExtension(disp.queryString.extensions, "EGL_KHR_gl_colorspace");
// Note: CDD requires that devices supporting wide color and/or HDR color also support
@@ -361,6 +371,7 @@
findExtension(disp.queryString.extensions, "EGL_KHR_image_gl_colorspace")) {
mExtensionString.append("EGL_EXT_image_gl_colorspace ");
}
+
if (findExtension(disp.queryString.extensions, ext.c_str(), len)) {
mExtensionString.append(ext + " ");
}
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index 0527c8a..2bca14d 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -84,7 +84,8 @@
// Extensions implemented by the EGL wrapper.
const char* const gBuiltinExtensionString =
"EGL_ANDROID_front_buffer_auto_refresh "
- "EGL_ANDROID_get_frame_timestamps "
+ // b/269060366 Conditionally enabled during display initialization:
+ //"EGL_ANDROID_get_frame_timestamps "
"EGL_ANDROID_get_native_client_buffer "
"EGL_ANDROID_presentation_time "
"EGL_EXT_surface_CTA861_3_metadata "
@@ -2185,6 +2186,10 @@
return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
}
+ if (!dp->haveExtension("EGL_ANDROID_get_frame_timestamps")) {
+ return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
+ }
+
SurfaceRef _s(dp, surface);
if (!_s.get()) {
return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
@@ -2218,6 +2223,10 @@
return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
}
+ if (!dp->haveExtension("EGL_ANDROID_get_frame_timestamps")) {
+ return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
+ }
+
SurfaceRef _s(dp, surface);
if (!_s.get()) {
return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
@@ -2272,6 +2281,10 @@
return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
}
+ if (!dp->haveExtension("EGL_ANDROID_get_frame_timestamps")) {
+ return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
+ }
+
SurfaceRef _s(dp, surface);
if (!_s.get()) {
return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
@@ -2302,6 +2315,10 @@
return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
}
+ if (!dp->haveExtension("EGL_ANDROID_get_frame_timestamps")) {
+ return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
+ }
+
SurfaceRef _s(dp, surface);
if (!_s.get()) {
return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
@@ -2387,6 +2404,10 @@
return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
}
+ if (!dp->haveExtension("EGL_ANDROID_get_frame_timestamps")) {
+ return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
+ }
+
SurfaceRef _s(dp, surface);
if (!_s.get()) {
return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
diff --git a/services/gpuservice/tests/unittests/Android.bp b/services/gpuservice/tests/unittests/Android.bp
index 86f6c7f..51642f9 100644
--- a/services/gpuservice/tests/unittests/Android.bp
+++ b/services/gpuservice/tests/unittests/Android.bp
@@ -24,9 +24,6 @@
cc_test {
name: "gpuservice_unittest",
test_suites: ["device-tests"],
- sanitize: {
- address: true,
- },
srcs: [
"GpuMemTest.cpp",
"GpuMemTracerTest.cpp",
diff --git a/services/gpuservice/vts/OWNERS b/services/gpuservice/vts/OWNERS
index e789052..a63de1c 100644
--- a/services/gpuservice/vts/OWNERS
+++ b/services/gpuservice/vts/OWNERS
@@ -1,4 +1,5 @@
# Bug component: 653544
+kocdemir@google.com
paulthomson@google.com
pbaiget@google.com
lfy@google.com
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 78cdd0d..cd427f0 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -110,6 +110,8 @@
constexpr int LOGTAG_INPUT_FOCUS = 62001;
constexpr int LOGTAG_INPUT_CANCEL = 62003;
+const ui::Transform kIdentityTransform;
+
inline nsecs_t now() {
return systemTime(SYSTEM_TIME_MONOTONIC);
}
@@ -475,8 +477,8 @@
}
// Returns true if the given window can accept pointer events at the given display location.
-bool windowAcceptsTouchAt(const WindowInfo& windowInfo, int32_t displayId, int32_t x, int32_t y,
- bool isStylus) {
+bool windowAcceptsTouchAt(const WindowInfo& windowInfo, int32_t displayId, float x, float y,
+ bool isStylus, const ui::Transform& displayTransform) {
const auto inputConfig = windowInfo.inputConfig;
if (windowInfo.displayId != displayId ||
inputConfig.test(WindowInfo::InputConfig::NOT_VISIBLE)) {
@@ -486,7 +488,17 @@
if (inputConfig.test(WindowInfo::InputConfig::NOT_TOUCHABLE) && !windowCanInterceptTouch) {
return false;
}
- if (!windowInfo.touchableRegionContainsPoint(x, y)) {
+
+ // Window Manager works in the logical display coordinate space. When it specifies bounds for a
+ // window as (l, t, r, b), the range of x in [l, r) and y in [t, b) are considered to be inside
+ // the window. Points on the right and bottom edges should not be inside the window, so we need
+ // to be careful about performing a hit test when the display is rotated, since the "right" and
+ // "bottom" of the window will be different in the display (un-rotated) space compared to in the
+ // logical display in which WM determined the bounds. Perform the hit test in the logical
+ // display space to ensure these edges are considered correctly in all orientations.
+ const auto touchableRegion = displayTransform.transform(windowInfo.touchableRegion);
+ const auto p = displayTransform.transform(x, y);
+ if (!touchableRegion.contains(std::floor(p.x), std::floor(p.y))) {
return false;
}
return true;
@@ -540,19 +552,16 @@
return {};
}
-Point resolveTouchedPosition(const MotionEntry& entry) {
+std::pair<float, float> resolveTouchedPosition(const MotionEntry& entry) {
const bool isFromMouse = isFromSource(entry.source, AINPUT_SOURCE_MOUSE);
// Always dispatch mouse events to cursor position.
if (isFromMouse) {
- return Point(static_cast<int32_t>(entry.xCursorPosition),
- static_cast<int32_t>(entry.yCursorPosition));
+ return {entry.xCursorPosition, entry.yCursorPosition};
}
const int32_t pointerIndex = getMotionEventActionPointerIndex(entry.action);
- return Point(static_cast<int32_t>(
- entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_X)),
- static_cast<int32_t>(
- entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y)));
+ return {entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_X),
+ entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y)};
}
std::optional<nsecs_t> getDownTime(const EventEntry& eventEntry) {
@@ -1159,7 +1168,7 @@
}
std::pair<sp<WindowInfoHandle>, std::vector<InputTarget>>
-InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y, bool isStylus,
+InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, float x, float y, bool isStylus,
bool ignoreDragWindow) const {
// Traverse windows from front to back to find touched window.
std::vector<InputTarget> outsideTargets;
@@ -1170,7 +1179,8 @@
}
const WindowInfo& info = *windowHandle->getInfo();
- if (!info.isSpy() && windowAcceptsTouchAt(info, displayId, x, y, isStylus)) {
+ if (!info.isSpy() &&
+ windowAcceptsTouchAt(info, displayId, x, y, isStylus, getTransformLocked(displayId))) {
return {windowHandle, outsideTargets};
}
@@ -1184,14 +1194,14 @@
}
std::vector<sp<WindowInfoHandle>> InputDispatcher::findTouchedSpyWindowsAtLocked(
- int32_t displayId, int32_t x, int32_t y, bool isStylus) const {
+ int32_t displayId, float x, float y, bool isStylus) const {
// Traverse windows from front to back and gather the touched spy windows.
std::vector<sp<WindowInfoHandle>> spyWindows;
const auto& windowHandles = getWindowHandlesLocked(displayId);
for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {
const WindowInfo& info = *windowHandle->getInfo();
- if (!windowAcceptsTouchAt(info, displayId, x, y, isStylus)) {
+ if (!windowAcceptsTouchAt(info, displayId, x, y, isStylus, getTransformLocked(displayId))) {
continue;
}
if (!info.isSpy()) {
@@ -2231,8 +2241,7 @@
}
// Handle the case where we did not find a window.
if (newTouchedWindowHandle == nullptr) {
- ALOGD("No new touched window at (%" PRId32 ", %" PRId32 ") in display %" PRId32, x, y,
- displayId);
+ ALOGD("No new touched window at (%.1f, %.1f) in display %" PRId32, x, y, displayId);
// Try to assign the pointer to the first foreground window we find, if there is one.
newTouchedWindowHandle = tempTouchState.getFirstForegroundWindowHandle();
}
@@ -2270,7 +2279,8 @@
}
if (newTouchedWindows.empty()) {
- ALOGI("Dropping event because there is no touchable window at (%d, %d) on display %d.",
+ ALOGI("Dropping event because there is no touchable window at (%.1f, %.1f) on display "
+ "%d.",
x, y, displayId);
outInjectionResult = InputEventInjectionResult::FAILED;
return {};
@@ -4764,6 +4774,12 @@
return getWindowHandleLocked(focusedToken, displayId);
}
+ui::Transform InputDispatcher::getTransformLocked(int32_t displayId) const {
+ auto displayInfoIt = mDisplayInfos.find(displayId);
+ return displayInfoIt != mDisplayInfos.end() ? displayInfoIt->second.transform
+ : kIdentityTransform;
+}
+
bool InputDispatcher::canWindowReceiveMotionLocked(const sp<WindowInfoHandle>& window,
const MotionEntry& motionEntry) const {
const WindowInfo& info = *window->getInfo();
@@ -4801,7 +4817,7 @@
TouchOcclusionInfo occlusionInfo = computeTouchOcclusionInfoLocked(window, x, y);
if (!isTouchTrustedLocked(occlusionInfo)) {
if (DEBUG_TOUCH_OCCLUSION) {
- ALOGD("Stack of obscuring windows during untrusted touch (%d, %d):", x, y);
+ ALOGD("Stack of obscuring windows during untrusted touch (%.1f, %.1f):", x, y);
for (const auto& log : occlusionInfo.debugInfo) {
ALOGD("%s", log.c_str());
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index b94858b..2246d47 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -239,11 +239,11 @@
std::shared_ptr<EventEntry> mNextUnblockedEvent GUARDED_BY(mLock);
std::pair<sp<android::gui::WindowInfoHandle>, std::vector<InputTarget>>
- findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y, bool isStylus = false,
+ findTouchedWindowAtLocked(int32_t displayId, float x, float y, bool isStylus = false,
bool ignoreDragWindow = false) const REQUIRES(mLock);
std::vector<sp<android::gui::WindowInfoHandle>> findTouchedSpyWindowsAtLocked(
- int32_t displayId, int32_t x, int32_t y, bool isStylus) const REQUIRES(mLock);
+ int32_t displayId, float x, float y, bool isStylus) const REQUIRES(mLock);
sp<android::gui::WindowInfoHandle> findTouchedForegroundWindowLocked(int32_t displayId) const
REQUIRES(mLock);
@@ -374,6 +374,7 @@
int32_t displayId) const REQUIRES(mLock);
sp<android::gui::WindowInfoHandle> getWindowHandleLocked(
const sp<IBinder>& windowHandleToken) const REQUIRES(mLock);
+ ui::Transform getTransformLocked(int32_t displayId) const REQUIRES(mLock);
// Same function as above, but faster. Since displayId is provided, this avoids the need
// to loop through all displays.
diff --git a/services/inputflinger/host/InputDriver.cpp b/services/inputflinger/host/InputDriver.cpp
index 97d57e4..ec0388d 100644
--- a/services/inputflinger/host/InputDriver.cpp
+++ b/services/inputflinger/host/InputDriver.cpp
@@ -242,13 +242,13 @@
input_property_t* InputDriver::inputGetDeviceProperty(input_property_map_t* map, const char* key) {
if (map != nullptr) {
- std::string value;
- auto prop = std::make_unique<input_property_t>();
- if (!map->propertyMap->tryGetProperty(key, value)) {
+ std::optional<std::string> value = map->propertyMap->getString(key);
+ if (!value.has_value()) {
return nullptr;
}
+ auto prop = std::make_unique<input_property_t>();
prop->key = key;
- prop->value = value.c_str();
+ prop->value = value->c_str();
return prop.release();
}
return nullptr;
diff --git a/services/inputflinger/include/PointerControllerInterface.h b/services/inputflinger/include/PointerControllerInterface.h
index 9dbdd5a..3f1ff30 100644
--- a/services/inputflinger/include/PointerControllerInterface.h
+++ b/services/inputflinger/include/PointerControllerInterface.h
@@ -22,6 +22,20 @@
namespace android {
+struct FloatPoint {
+ float x;
+ float y;
+
+ inline FloatPoint(float x, float y) : x(x), y(y) {}
+
+ inline explicit FloatPoint(vec2 p) : x(p.x), y(p.y) {}
+
+ template <typename T, typename U>
+ operator std::tuple<T, U>() {
+ return {x, y};
+ }
+};
+
/**
* Interface for tracking a mouse / touch pad pointer and touch pad spots.
*
@@ -40,8 +54,7 @@
public:
/* Gets the bounds of the region that the pointer can traverse.
* Returns true if the bounds are available. */
- virtual bool getBounds(float* outMinX, float* outMinY,
- float* outMaxX, float* outMaxY) const = 0;
+ virtual std::optional<FloatRect> getBounds() const = 0;
/* Move the pointer. */
virtual void move(float deltaX, float deltaY) = 0;
@@ -56,7 +69,7 @@
virtual void setPosition(float x, float y) = 0;
/* Gets the absolute location of the pointer. */
- virtual void getPosition(float* outX, float* outY) const = 0;
+ virtual FloatPoint getPosition() const = 0;
enum class Transition {
// Fade/unfade immediately.
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 3d3a8ea..e65f3af 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -52,6 +52,7 @@
#include <utils/Timers.h>
#include <filesystem>
+#include <optional>
#include <regex>
#include <utility>
@@ -673,9 +674,9 @@
bool EventHub::Device::isExternalDeviceLocked() {
if (configuration) {
- bool value;
- if (configuration->tryGetProperty("device.internal", value)) {
- return !value;
+ std::optional<bool> isInternal = configuration->getBool("device.internal");
+ if (isInternal.has_value()) {
+ return !isInternal.value();
}
}
return identifier.bus == BUS_USB || identifier.bus == BUS_BLUETOOTH;
@@ -683,9 +684,9 @@
bool EventHub::Device::deviceHasMicLocked() {
if (configuration) {
- bool value;
- if (configuration->tryGetProperty("audio.mic", value)) {
- return value;
+ std::optional<bool> hasMic = configuration->getBool("audio.mic");
+ if (hasMic.has_value()) {
+ return hasMic.value();
}
}
return false;
@@ -2281,8 +2282,8 @@
}
// See if the device is specially configured to be of a certain type.
- std::string deviceType;
- if (device->configuration && device->configuration->tryGetProperty("device.type", deviceType)) {
+ if (device->configuration) {
+ std::string deviceType = device->configuration->getString("device.type").value_or("");
if (deviceType == "rotaryEncoder") {
device->classes |= InputDeviceClass::ROTARY_ENCODER;
} else if (deviceType == "externalStylus") {
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index 0d2030e..69363b6 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -210,14 +210,13 @@
// Touchscreens and touchpad devices.
static const bool ENABLE_TOUCHPAD_GESTURES_LIBRARY =
sysprop::InputProperties::enable_touchpad_gestures_library().value_or(true);
- // TODO(b/246587538): Fix the new touchpad stack for Sony DualShock 4 (5c4, 9cc) and DualSense
- // (ce6) touchpads, or at least load this setting from the IDC file.
+ // TODO(b/272518665): Fix the new touchpad stack for Sony DualShock 4 (5c4, 9cc) touchpads, or
+ // at least load this setting from the IDC file.
const InputDeviceIdentifier identifier = contextPtr->getDeviceIdentifier();
- const bool isSonyGamepadTouchpad = identifier.vendor == 0x054c &&
- (identifier.product == 0x05c4 || identifier.product == 0x09cc ||
- identifier.product == 0x0ce6);
+ const bool isSonyDualShock4Touchpad = identifier.vendor == 0x054c &&
+ (identifier.product == 0x05c4 || identifier.product == 0x09cc);
if (ENABLE_TOUCHPAD_GESTURES_LIBRARY && classes.test(InputDeviceClass::TOUCHPAD) &&
- classes.test(InputDeviceClass::TOUCH_MT) && !isSonyGamepadTouchpad) {
+ classes.test(InputDeviceClass::TOUCH_MT) && !isSonyDualShock4Touchpad) {
mappers.push_back(std::make_unique<TouchpadInputMapper>(*contextPtr));
} else if (classes.test(InputDeviceClass::TOUCH_MT)) {
mappers.push_back(std::make_unique<MultiTouchInputMapper>(*contextPtr));
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index 13e4d0c..b12a009 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -20,6 +20,8 @@
#include "CursorInputMapper.h"
+#include <optional>
+
#include "CursorButtonAccumulator.h"
#include "CursorScrollAccumulator.h"
#include "PointerControllerInterface.h"
@@ -83,10 +85,11 @@
InputMapper::populateDeviceInfo(info);
if (mParameters.mode == Parameters::Mode::POINTER) {
- float minX, minY, maxX, maxY;
- if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) {
- info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, minX, maxX, 0.0f, 0.0f, 0.0f);
- info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, minY, maxY, 0.0f, 0.0f, 0.0f);
+ if (const auto bounds = mPointerController->getBounds(); bounds) {
+ info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, bounds->left, bounds->right, 0.0f,
+ 0.0f, 0.0f);
+ info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, bounds->top, bounds->bottom, 0.0f,
+ 0.0f, 0.0f);
}
} else {
info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, -1.0f, 1.0f, 0.0f, mXScale, 0.0f);
@@ -250,18 +253,17 @@
void CursorInputMapper::configureParameters() {
mParameters.mode = Parameters::Mode::POINTER;
- std::string cursorModeString;
- if (getDeviceContext().getConfiguration().tryGetProperty("cursor.mode", cursorModeString)) {
- if (cursorModeString == "navigation") {
+ const PropertyMap& config = getDeviceContext().getConfiguration();
+ std::optional<std::string> cursorModeString = config.getString("cursor.mode");
+ if (cursorModeString.has_value()) {
+ if (*cursorModeString == "navigation") {
mParameters.mode = Parameters::Mode::NAVIGATION;
- } else if (cursorModeString != "pointer" && cursorModeString != "default") {
- ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.c_str());
+ } else if (*cursorModeString != "pointer" && *cursorModeString != "default") {
+ ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString->c_str());
}
}
- mParameters.orientationAware = false;
- getDeviceContext().getConfiguration().tryGetProperty("cursor.orientationAware",
- mParameters.orientationAware);
+ mParameters.orientationAware = config.getBool("cursor.orientationAware").value_or(false);
mParameters.hasAssociatedDisplay = false;
if (mParameters.mode == Parameters::Mode::POINTER || mParameters.orientationAware) {
@@ -379,7 +381,7 @@
mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
}
- mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
+ std::tie(xCursorPosition, yCursorPosition) = mPointerController->getPosition();
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition);
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
index dc0454d..f39e004 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -154,15 +154,10 @@
}
void KeyboardInputMapper::configureParameters() {
- mParameters.orientationAware = false;
const PropertyMap& config = getDeviceContext().getConfiguration();
- config.tryGetProperty("keyboard.orientationAware", mParameters.orientationAware);
-
- mParameters.handlesKeyRepeat = false;
- config.tryGetProperty("keyboard.handlesKeyRepeat", mParameters.handlesKeyRepeat);
-
- mParameters.doNotWakeByDefault = false;
- config.tryGetProperty("keyboard.doNotWakeByDefault", mParameters.doNotWakeByDefault);
+ mParameters.orientationAware = config.getBool("keyboard.orientationAware").value_or(false);
+ mParameters.handlesKeyRepeat = config.getBool("keyboard.handlesKeyRepeat").value_or(false);
+ mParameters.doNotWakeByDefault = config.getBool("keyboard.doNotWakeByDefault").value_or(false);
}
void KeyboardInputMapper::dumpParameters(std::string& dump) const {
diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
index 19a79d7..2ff26ed 100644
--- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
@@ -20,6 +20,8 @@
#include "RotaryEncoderInputMapper.h"
+#include <optional>
+
#include "CursorScrollAccumulator.h"
namespace android {
@@ -39,18 +41,19 @@
InputMapper::populateDeviceInfo(info);
if (mRotaryEncoderScrollAccumulator.haveRelativeVWheel()) {
- float res = 0.0f;
- if (!getDeviceContext().getConfiguration().tryGetProperty("device.res", res)) {
+ const PropertyMap& config = getDeviceContext().getConfiguration();
+ std::optional<float> res = config.getFloat("device.res");
+ if (!res.has_value()) {
ALOGW("Rotary Encoder device configuration file didn't specify resolution!\n");
}
- if (!getDeviceContext().getConfiguration().tryGetProperty("device.scalingFactor",
- mScalingFactor)) {
+ std::optional<float> scalingFactor = config.getFloat("device.scalingFactor");
+ if (!scalingFactor.has_value()) {
ALOGW("Rotary Encoder device configuration file didn't specify scaling factor,"
"default to 1.0!\n");
- mScalingFactor = 1.0f;
}
+ mScalingFactor = scalingFactor.value_or(1.0f);
info->addMotionRange(AMOTION_EVENT_AXIS_SCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f,
- res * mScalingFactor);
+ res.value_or(0.0f) * mScalingFactor);
}
}
diff --git a/services/inputflinger/reader/mapper/SensorInputMapper.cpp b/services/inputflinger/reader/mapper/SensorInputMapper.cpp
index f797bc9..ba08823 100644
--- a/services/inputflinger/reader/mapper/SensorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/SensorInputMapper.cpp
@@ -61,12 +61,6 @@
return AINPUT_SOURCE_SENSOR;
}
-template <typename T>
-bool SensorInputMapper::tryGetProperty(std::string keyName, T& outValue) {
- const auto& config = getDeviceContext().getConfiguration();
- return config.tryGetProperty(keyName, outValue);
-}
-
void SensorInputMapper::parseSensorConfiguration(InputDeviceSensorType sensorType, int32_t absCode,
int32_t sensorDataIndex, const Axis& axis) {
auto it = mSensors.find(sensorType);
@@ -201,6 +195,17 @@
SensorInputMapper::Sensor SensorInputMapper::createSensor(InputDeviceSensorType sensorType,
const Axis& axis) {
InputDeviceIdentifier identifier = getDeviceContext().getDeviceIdentifier();
+ const auto& config = getDeviceContext().getConfiguration();
+
+ std::string prefix = "sensor." + ftl::enum_string(sensorType);
+ transform(prefix.begin(), prefix.end(), prefix.begin(), ::tolower);
+
+ int32_t flags = 0;
+ std::optional<int32_t> reportingMode = config.getInt(prefix + ".reportingMode");
+ if (reportingMode.has_value()) {
+ flags |= (*reportingMode & REPORTING_MODE_MASK) << REPORTING_MODE_SHIFT;
+ }
+
// Sensor Id will be assigned to device Id to distinguish same sensor from multiple input
// devices, in such a way that the sensor Id will be same as input device Id.
// The sensorType is to distinguish different sensors within one device.
@@ -209,28 +214,15 @@
identifier.version, sensorType,
InputDeviceSensorAccuracy::ACCURACY_HIGH,
/*maxRange=*/axis.max, /*resolution=*/axis.scale,
- /*power=*/0.0f, /*minDelay=*/0,
- /*fifoReservedEventCount=*/0, /*fifoMaxEventCount=*/0,
- ftl::enum_string(sensorType), /*maxDelay=*/0, /*flags=*/0,
- getDeviceId());
-
- std::string prefix = "sensor." + ftl::enum_string(sensorType);
- transform(prefix.begin(), prefix.end(), prefix.begin(), ::tolower);
-
- int32_t reportingMode = 0;
- if (!tryGetProperty(prefix + ".reportingMode", reportingMode)) {
- sensorInfo.flags |= (reportingMode & REPORTING_MODE_MASK) << REPORTING_MODE_SHIFT;
- }
-
- tryGetProperty(prefix + ".maxDelay", sensorInfo.maxDelay);
-
- tryGetProperty(prefix + ".minDelay", sensorInfo.minDelay);
-
- tryGetProperty(prefix + ".power", sensorInfo.power);
-
- tryGetProperty(prefix + ".fifoReservedEventCount", sensorInfo.fifoReservedEventCount);
-
- tryGetProperty(prefix + ".fifoMaxEventCount", sensorInfo.fifoMaxEventCount);
+ /*power=*/config.getFloat(prefix + ".power").value_or(0.0f),
+ /*minDelay=*/config.getInt(prefix + ".minDelay").value_or(0),
+ /*fifoReservedEventCount=*/
+ config.getInt(prefix + ".fifoReservedEventCount").value_or(0),
+ /*fifoMaxEventCount=*/
+ config.getInt(prefix + ".fifoMaxEventCount").value_or(0),
+ ftl::enum_string(sensorType),
+ /*maxDelay=*/config.getInt(prefix + ".maxDelay").value_or(0),
+ /*flags=*/flags, getDeviceId());
return Sensor(sensorInfo);
}
diff --git a/services/inputflinger/reader/mapper/SensorInputMapper.h b/services/inputflinger/reader/mapper/SensorInputMapper.h
index 457567b..043a895 100644
--- a/services/inputflinger/reader/mapper/SensorInputMapper.h
+++ b/services/inputflinger/reader/mapper/SensorInputMapper.h
@@ -16,6 +16,9 @@
#pragma once
+#include <optional>
+#include <string>
+
#include "InputMapper.h"
namespace android {
@@ -120,9 +123,6 @@
[[nodiscard]] std::list<NotifyArgs> sync(nsecs_t when, bool force);
- template <typename T>
- bool tryGetProperty(std::string keyName, T& outValue);
-
void parseSensorConfiguration(InputDeviceSensorType sensorType, int32_t absCode,
int32_t sensorDataIndex, const Axis& axis);
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index b53fc73..a943a03 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -366,15 +366,15 @@
? Parameters::GestureMode::SINGLE_TOUCH
: Parameters::GestureMode::MULTI_TOUCH;
- std::string gestureModeString;
- if (getDeviceContext().getConfiguration().tryGetProperty("touch.gestureMode",
- gestureModeString)) {
- if (gestureModeString == "single-touch") {
+ const PropertyMap& config = getDeviceContext().getConfiguration();
+ std::optional<std::string> gestureModeString = config.getString("touch.gestureMode");
+ if (gestureModeString.has_value()) {
+ if (*gestureModeString == "single-touch") {
mParameters.gestureMode = Parameters::GestureMode::SINGLE_TOUCH;
- } else if (gestureModeString == "multi-touch") {
+ } else if (*gestureModeString == "multi-touch") {
mParameters.gestureMode = Parameters::GestureMode::MULTI_TOUCH;
- } else if (gestureModeString != "default") {
- ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.c_str());
+ } else if (*gestureModeString != "default") {
+ ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString->c_str());
}
}
@@ -382,24 +382,23 @@
mParameters.hasButtonUnderPad = getDeviceContext().hasInputProperty(INPUT_PROP_BUTTONPAD);
- mParameters.orientationAware = mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN;
- getDeviceContext().getConfiguration().tryGetProperty("touch.orientationAware",
- mParameters.orientationAware);
+ mParameters.orientationAware =
+ config.getBool("touch.orientationAware")
+ .value_or(mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN);
mParameters.orientation = ui::ROTATION_0;
- std::string orientationString;
- if (getDeviceContext().getConfiguration().tryGetProperty("touch.orientation",
- orientationString)) {
+ std::optional<std::string> orientationString = config.getString("touch.orientation");
+ if (orientationString.has_value()) {
if (mParameters.deviceType != Parameters::DeviceType::TOUCH_SCREEN) {
ALOGW("The configuration 'touch.orientation' is only supported for touchscreens.");
- } else if (orientationString == "ORIENTATION_90") {
+ } else if (*orientationString == "ORIENTATION_90") {
mParameters.orientation = ui::ROTATION_90;
- } else if (orientationString == "ORIENTATION_180") {
+ } else if (*orientationString == "ORIENTATION_180") {
mParameters.orientation = ui::ROTATION_180;
- } else if (orientationString == "ORIENTATION_270") {
+ } else if (*orientationString == "ORIENTATION_270") {
mParameters.orientation = ui::ROTATION_270;
- } else if (orientationString != "ORIENTATION_0") {
- ALOGW("Invalid value for touch.orientation: '%s'", orientationString.c_str());
+ } else if (*orientationString != "ORIENTATION_0") {
+ ALOGW("Invalid value for touch.orientation: '%s'", orientationString->c_str());
}
}
@@ -413,10 +412,7 @@
mParameters.hasAssociatedDisplay = true;
if (mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN) {
mParameters.associatedDisplayIsExternal = getDeviceContext().isExternal();
- std::string uniqueDisplayId;
- getDeviceContext().getConfiguration().tryGetProperty("touch.displayId",
- uniqueDisplayId);
- mParameters.uniqueDisplayId = uniqueDisplayId.c_str();
+ mParameters.uniqueDisplayId = config.getString("touch.displayId").value_or("").c_str();
}
}
if (getDeviceContext().getAssociatedDisplayPort()) {
@@ -426,20 +422,19 @@
// Initial downs on external touch devices should wake the device.
// Normally we don't do this for internal touch screens to prevent them from waking
// up in your pocket but you can enable it using the input device configuration.
- mParameters.wake = getDeviceContext().isExternal();
- getDeviceContext().getConfiguration().tryGetProperty("touch.wake", mParameters.wake);
+ mParameters.wake = config.getBool("touch.wake").value_or(getDeviceContext().isExternal());
- InputDeviceUsiVersion usiVersion;
- if (getDeviceContext().getConfiguration().tryGetProperty("touch.usiVersionMajor",
- usiVersion.majorVersion) &&
- getDeviceContext().getConfiguration().tryGetProperty("touch.usiVersionMinor",
- usiVersion.minorVersion)) {
- mParameters.usiVersion = usiVersion;
+ std::optional<int32_t> usiVersionMajor = config.getInt("touch.usiVersionMajor");
+ std::optional<int32_t> usiVersionMinor = config.getInt("touch.usiVersionMinor");
+ if (usiVersionMajor.has_value() && usiVersionMinor.has_value()) {
+ mParameters.usiVersion = {
+ .majorVersion = *usiVersionMajor,
+ .minorVersion = *usiVersionMinor,
+ };
}
- mParameters.enableForInactiveViewport = false;
- getDeviceContext().getConfiguration().tryGetProperty("touch.enableForInactiveViewport",
- mParameters.enableForInactiveViewport);
+ mParameters.enableForInactiveViewport =
+ config.getBool("touch.enableForInactiveViewport").value_or(false);
}
void TouchInputMapper::configureDeviceType() {
@@ -457,7 +452,8 @@
// Type association takes precedence over the device type found in the idc file.
std::string deviceTypeString = getDeviceContext().getDeviceTypeAssociation().value_or("");
if (deviceTypeString.empty()) {
- getDeviceContext().getConfiguration().tryGetProperty("touch.deviceType", deviceTypeString);
+ deviceTypeString =
+ getDeviceContext().getConfiguration().getString("touch.deviceType").value_or("");
}
if (deviceTypeString == "touchScreen") {
mParameters.deviceType = Parameters::DeviceType::TOUCH_SCREEN;
@@ -805,40 +801,39 @@
};
}
- // Compute oriented precision, scales and ranges.
- // Note that the maximum value reported is an inclusive maximum value so it is one
- // unit less than the total width or height of the display.
- // TODO(b/20508709): Calculate the oriented ranges using the input device's raw frame.
- switch (mInputDeviceOrientation) {
- case ui::ROTATION_90:
- case ui::ROTATION_270:
- mOrientedRanges.x.min = 0;
- mOrientedRanges.x.max = mDisplayBounds.height - 1;
- mOrientedRanges.x.flat = 0;
- mOrientedRanges.x.fuzz = 0;
- mOrientedRanges.x.resolution = mRawPointerAxes.y.resolution * mRawToDisplay.getScaleY();
+ // Oriented X/Y range (in the rotated display's orientation)
+ const FloatRect rawFrame = Rect{mRawPointerAxes.x.minValue, mRawPointerAxes.y.minValue,
+ mRawPointerAxes.x.maxValue, mRawPointerAxes.y.maxValue}
+ .toFloatRect();
+ const auto orientedRangeRect = mRawToRotatedDisplay.transform(rawFrame);
+ mOrientedRanges.x.min = orientedRangeRect.left;
+ mOrientedRanges.y.min = orientedRangeRect.top;
+ mOrientedRanges.x.max = orientedRangeRect.right;
+ mOrientedRanges.y.max = orientedRangeRect.bottom;
- mOrientedRanges.y.min = 0;
- mOrientedRanges.y.max = mDisplayBounds.width - 1;
- mOrientedRanges.y.flat = 0;
- mOrientedRanges.y.fuzz = 0;
- mOrientedRanges.y.resolution = mRawPointerAxes.x.resolution * mRawToDisplay.getScaleX();
- break;
+ // Oriented flat (in the rotated display's orientation)
+ const auto orientedFlat =
+ transformWithoutTranslation(mRawToRotatedDisplay,
+ {static_cast<float>(mRawPointerAxes.x.flat),
+ static_cast<float>(mRawPointerAxes.y.flat)});
+ mOrientedRanges.x.flat = std::abs(orientedFlat.x);
+ mOrientedRanges.y.flat = std::abs(orientedFlat.y);
- default:
- mOrientedRanges.x.min = 0;
- mOrientedRanges.x.max = mDisplayBounds.width - 1;
- mOrientedRanges.x.flat = 0;
- mOrientedRanges.x.fuzz = 0;
- mOrientedRanges.x.resolution = mRawPointerAxes.x.resolution * mRawToDisplay.getScaleX();
+ // Oriented fuzz (in the rotated display's orientation)
+ const auto orientedFuzz =
+ transformWithoutTranslation(mRawToRotatedDisplay,
+ {static_cast<float>(mRawPointerAxes.x.fuzz),
+ static_cast<float>(mRawPointerAxes.y.fuzz)});
+ mOrientedRanges.x.fuzz = std::abs(orientedFuzz.x);
+ mOrientedRanges.y.fuzz = std::abs(orientedFuzz.y);
- mOrientedRanges.y.min = 0;
- mOrientedRanges.y.max = mDisplayBounds.height - 1;
- mOrientedRanges.y.flat = 0;
- mOrientedRanges.y.fuzz = 0;
- mOrientedRanges.y.resolution = mRawPointerAxes.y.resolution * mRawToDisplay.getScaleY();
- break;
- }
+ // Oriented resolution (in the rotated display's orientation)
+ const auto orientedRes =
+ transformWithoutTranslation(mRawToRotatedDisplay,
+ {static_cast<float>(mRawPointerAxes.x.resolution),
+ static_cast<float>(mRawPointerAxes.y.resolution)});
+ mOrientedRanges.x.resolution = std::abs(orientedRes.x);
+ mOrientedRanges.y.resolution = std::abs(orientedRes.y);
}
void TouchInputMapper::computeInputTransforms() {
@@ -1161,92 +1156,79 @@
// Size
out.sizeCalibration = Calibration::SizeCalibration::DEFAULT;
- std::string sizeCalibrationString;
- if (in.tryGetProperty("touch.size.calibration", sizeCalibrationString)) {
- if (sizeCalibrationString == "none") {
+ std::optional<std::string> sizeCalibrationString = in.getString("touch.size.calibration");
+ if (sizeCalibrationString.has_value()) {
+ if (*sizeCalibrationString == "none") {
out.sizeCalibration = Calibration::SizeCalibration::NONE;
- } else if (sizeCalibrationString == "geometric") {
+ } else if (*sizeCalibrationString == "geometric") {
out.sizeCalibration = Calibration::SizeCalibration::GEOMETRIC;
- } else if (sizeCalibrationString == "diameter") {
+ } else if (*sizeCalibrationString == "diameter") {
out.sizeCalibration = Calibration::SizeCalibration::DIAMETER;
- } else if (sizeCalibrationString == "box") {
+ } else if (*sizeCalibrationString == "box") {
out.sizeCalibration = Calibration::SizeCalibration::BOX;
- } else if (sizeCalibrationString == "area") {
+ } else if (*sizeCalibrationString == "area") {
out.sizeCalibration = Calibration::SizeCalibration::AREA;
- } else if (sizeCalibrationString != "default") {
- ALOGW("Invalid value for touch.size.calibration: '%s'", sizeCalibrationString.c_str());
+ } else if (*sizeCalibrationString != "default") {
+ ALOGW("Invalid value for touch.size.calibration: '%s'", sizeCalibrationString->c_str());
}
}
- float sizeScale;
-
- if (in.tryGetProperty("touch.size.scale", sizeScale)) {
- out.sizeScale = sizeScale;
- }
- float sizeBias;
- if (in.tryGetProperty("touch.size.bias", sizeBias)) {
- out.sizeBias = sizeBias;
- }
- bool sizeIsSummed;
- if (in.tryGetProperty("touch.size.isSummed", sizeIsSummed)) {
- out.sizeIsSummed = sizeIsSummed;
- }
+ out.sizeScale = in.getFloat("touch.size.scale");
+ out.sizeBias = in.getFloat("touch.size.bias");
+ out.sizeIsSummed = in.getBool("touch.size.isSummed");
// Pressure
out.pressureCalibration = Calibration::PressureCalibration::DEFAULT;
- std::string pressureCalibrationString;
- if (in.tryGetProperty("touch.pressure.calibration", pressureCalibrationString)) {
- if (pressureCalibrationString == "none") {
+ std::optional<std::string> pressureCalibrationString =
+ in.getString("touch.pressure.calibration");
+ if (pressureCalibrationString.has_value()) {
+ if (*pressureCalibrationString == "none") {
out.pressureCalibration = Calibration::PressureCalibration::NONE;
- } else if (pressureCalibrationString == "physical") {
+ } else if (*pressureCalibrationString == "physical") {
out.pressureCalibration = Calibration::PressureCalibration::PHYSICAL;
- } else if (pressureCalibrationString == "amplitude") {
+ } else if (*pressureCalibrationString == "amplitude") {
out.pressureCalibration = Calibration::PressureCalibration::AMPLITUDE;
- } else if (pressureCalibrationString != "default") {
+ } else if (*pressureCalibrationString != "default") {
ALOGW("Invalid value for touch.pressure.calibration: '%s'",
- pressureCalibrationString.c_str());
+ pressureCalibrationString->c_str());
}
}
- float pressureScale;
- if (in.tryGetProperty("touch.pressure.scale", pressureScale)) {
- out.pressureScale = pressureScale;
- }
+ out.pressureScale = in.getFloat("touch.pressure.scale");
// Orientation
out.orientationCalibration = Calibration::OrientationCalibration::DEFAULT;
- std::string orientationCalibrationString;
- if (in.tryGetProperty("touch.orientation.calibration", orientationCalibrationString)) {
- if (orientationCalibrationString == "none") {
+ std::optional<std::string> orientationCalibrationString =
+ in.getString("touch.orientation.calibration");
+ if (orientationCalibrationString.has_value()) {
+ if (*orientationCalibrationString == "none") {
out.orientationCalibration = Calibration::OrientationCalibration::NONE;
- } else if (orientationCalibrationString == "interpolated") {
+ } else if (*orientationCalibrationString == "interpolated") {
out.orientationCalibration = Calibration::OrientationCalibration::INTERPOLATED;
- } else if (orientationCalibrationString == "vector") {
+ } else if (*orientationCalibrationString == "vector") {
out.orientationCalibration = Calibration::OrientationCalibration::VECTOR;
- } else if (orientationCalibrationString != "default") {
+ } else if (*orientationCalibrationString != "default") {
ALOGW("Invalid value for touch.orientation.calibration: '%s'",
- orientationCalibrationString.c_str());
+ orientationCalibrationString->c_str());
}
}
// Distance
out.distanceCalibration = Calibration::DistanceCalibration::DEFAULT;
- std::string distanceCalibrationString;
- if (in.tryGetProperty("touch.distance.calibration", distanceCalibrationString)) {
- if (distanceCalibrationString == "none") {
+ std::optional<std::string> distanceCalibrationString =
+ in.getString("touch.distance.calibration");
+ if (distanceCalibrationString.has_value()) {
+ if (*distanceCalibrationString == "none") {
out.distanceCalibration = Calibration::DistanceCalibration::NONE;
- } else if (distanceCalibrationString == "scaled") {
+ } else if (*distanceCalibrationString == "scaled") {
out.distanceCalibration = Calibration::DistanceCalibration::SCALED;
- } else if (distanceCalibrationString != "default") {
+ } else if (*distanceCalibrationString != "default") {
ALOGW("Invalid value for touch.distance.calibration: '%s'",
- distanceCalibrationString.c_str());
+ distanceCalibrationString->c_str());
}
}
- float distanceScale;
- if (in.tryGetProperty("touch.distance.scale", distanceScale)) {
- out.distanceScale = distanceScale;
- }
+ out.distanceScale = in.getFloat("touch.distance.scale");
}
void TouchInputMapper::resolveCalibration() {
@@ -2692,8 +2674,7 @@
// the pointer is hovering again even if the user is not currently touching
// the touch pad. This ensures that a view will receive a fresh hover enter
// event after a tap.
- float x, y;
- mPointerController->getPosition(&x, &y);
+ const auto [x, y] = mPointerController->getPosition();
PointerProperties pointerProperties;
pointerProperties.clear();
@@ -2899,8 +2880,7 @@
mPointerVelocityControl.reset();
}
- float x, y;
- mPointerController->getPosition(&x, &y);
+ const auto [x, y] = mPointerController->getPosition();
mPointerGesture.currentGestureMode = PointerGesture::Mode::BUTTON_CLICK_OR_DRAG;
mPointerGesture.currentGestureIdBits.clear();
@@ -2926,8 +2906,7 @@
mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP_DRAG) &&
lastFingerCount == 1) {
if (when <= mPointerGesture.tapDownTime + mConfig.pointerGestureTapInterval) {
- float x, y;
- mPointerController->getPosition(&x, &y);
+ const auto [x, y] = mPointerController->getPosition();
if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop &&
fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) {
ALOGD_IF(DEBUG_GESTURES, "Gestures: TAP");
@@ -2989,8 +2968,7 @@
mPointerGesture.currentGestureMode = PointerGesture::Mode::HOVER;
if (mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP) {
if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) {
- float x, y;
- mPointerController->getPosition(&x, &y);
+ const auto [x, y] = mPointerController->getPosition();
if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop &&
fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) {
mPointerGesture.currentGestureMode = PointerGesture::Mode::TAP_DRAG;
@@ -3026,8 +3004,7 @@
down = false;
}
- float x, y;
- mPointerController->getPosition(&x, &y);
+ const auto [x, y] = mPointerController->getPosition();
mPointerGesture.currentGestureIdBits.clear();
mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
@@ -3194,8 +3171,8 @@
mCurrentRawState.rawPointerData
.getCentroidOfTouchingPointers(&mPointerGesture.referenceTouchX,
&mPointerGesture.referenceTouchY);
- mPointerController->getPosition(&mPointerGesture.referenceGestureX,
- &mPointerGesture.referenceGestureY);
+ std::tie(mPointerGesture.referenceGestureX, mPointerGesture.referenceGestureY) =
+ mPointerController->getPosition();
}
// Clear the reference deltas for fingers not yet included in the reference calculation.
@@ -3510,8 +3487,7 @@
hovering = mCurrentCookedState.cookedPointerData.hoveringIdBits.hasBit(id);
down = !hovering;
- float x, y;
- mPointerController->getPosition(&x, &y);
+ const auto [x, y] = mPointerController->getPosition();
mPointerSimple.currentCoords.copyFrom(
mCurrentCookedState.cookedPointerData.pointerCoords[index]);
mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
@@ -3549,9 +3525,8 @@
down = isPointerDown(mCurrentRawState.buttonState);
hovering = !down;
- float x, y;
- mPointerController->getPosition(&x, &y);
- uint32_t currentIndex = mCurrentRawState.rawPointerData.idToIndex[id];
+ const auto [x, y] = mPointerController->getPosition();
+ const uint32_t currentIndex = mCurrentRawState.rawPointerData.idToIndex[id];
mPointerSimple.currentCoords.copyFrom(
mCurrentCookedState.cookedPointerData.pointerCoords[currentIndex]);
mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
@@ -3598,8 +3573,7 @@
}
int32_t displayId = mPointerController->getDisplayId();
- float xCursorPosition, yCursorPosition;
- mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
+ const auto [xCursorPosition, yCursorPosition] = mPointerController->getPosition();
if (mPointerSimple.down && !down) {
mPointerSimple.down = false;
@@ -3820,7 +3794,7 @@
float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
if (mDeviceMode == DeviceMode::POINTER) {
- mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
+ std::tie(xCursorPosition, yCursorPosition) = mPointerController->getPosition();
}
const int32_t deviceId = getDeviceId();
std::vector<TouchVideoFrame> frames = getDeviceContext().getVideoFrames();
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index 7b464ef..df66846 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -16,6 +16,9 @@
#pragma once
+#include <optional>
+#include <string>
+
#include <stdint.h>
#include <ui/Rotation.h>
diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
index d636d44..bc9f4c0 100644
--- a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
@@ -98,7 +98,6 @@
case kGestureTypePinch:
return handlePinch(when, readTime, gesture);
default:
- // TODO(b/251196347): handle more gesture types.
return {};
}
}
@@ -111,8 +110,8 @@
mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER);
mPointerController->move(deltaX, deltaY);
mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
- float xCursorPosition, yCursorPosition;
- mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
+
+ const auto [xCursorPosition, yCursorPosition] = mPointerController->getPosition();
PointerCoords coords;
coords.clear();
@@ -136,8 +135,7 @@
mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER);
mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
- float xCursorPosition, yCursorPosition;
- mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
+ const auto [xCursorPosition, yCursorPosition] = mPointerController->getPosition();
PointerCoords coords;
coords.clear();
@@ -202,18 +200,19 @@
const Gesture& gesture) {
std::list<NotifyArgs> out;
PointerCoords& coords = mFakeFingerCoords[0];
- float xCursorPosition, yCursorPosition;
- mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
+ const auto [xCursorPosition, yCursorPosition] = mPointerController->getPosition();
if (mCurrentClassification != MotionClassification::TWO_FINGER_SWIPE) {
mCurrentClassification = MotionClassification::TWO_FINGER_SWIPE;
coords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition);
coords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition);
coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
mDownTime = when;
- out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_DOWN,
- /* actionButton= */ 0, mButtonState, /* pointerCount= */ 1,
- mFingerProps.data(), mFakeFingerCoords.data(), xCursorPosition,
- yCursorPosition));
+ NotifyMotionArgs args =
+ makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_DOWN, /* actionButton= */ 0,
+ mButtonState, /* pointerCount= */ 1, mFingerProps.data(),
+ mFakeFingerCoords.data(), xCursorPosition, yCursorPosition);
+ args.flags |= AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE;
+ out.push_back(args);
}
float deltaX = gesture.details.scroll.dx;
float deltaY = gesture.details.scroll.dy;
@@ -224,9 +223,12 @@
// TODO(b/262876643): set AXIS_GESTURE_{X,Y}_OFFSET.
coords.setAxisValue(AMOTION_EVENT_AXIS_GESTURE_SCROLL_X_DISTANCE, -gesture.details.scroll.dx);
coords.setAxisValue(AMOTION_EVENT_AXIS_GESTURE_SCROLL_Y_DISTANCE, -gesture.details.scroll.dy);
- out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_MOVE, /* actionButton= */ 0,
- mButtonState, /* pointerCount= */ 1, mFingerProps.data(),
- mFakeFingerCoords.data(), xCursorPosition, yCursorPosition));
+ NotifyMotionArgs args =
+ makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_MOVE, /* actionButton= */ 0,
+ mButtonState, /* pointerCount= */ 1, mFingerProps.data(),
+ mFakeFingerCoords.data(), xCursorPosition, yCursorPosition);
+ args.flags |= AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE;
+ out.push_back(args);
return out;
}
@@ -239,14 +241,14 @@
return {};
}
- float xCursorPosition, yCursorPosition;
- mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
+ const auto [xCursorPosition, yCursorPosition] = mPointerController->getPosition();
mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_GESTURE_SCROLL_X_DISTANCE, 0);
mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_GESTURE_SCROLL_Y_DISTANCE, 0);
- NotifyArgs args = makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_UP,
- /* actionButton= */ 0, mButtonState, /* pointerCount= */ 1,
- mFingerProps.data(), mFakeFingerCoords.data(), xCursorPosition,
- yCursorPosition);
+ NotifyMotionArgs args =
+ makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_UP, /* actionButton= */ 0,
+ mButtonState, /* pointerCount= */ 1, mFingerProps.data(),
+ mFakeFingerCoords.data(), xCursorPosition, yCursorPosition);
+ args.flags |= AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE;
mCurrentClassification = MotionClassification::NONE;
return args;
}
@@ -256,8 +258,8 @@
uint32_t fingerCount,
float dx, float dy) {
std::list<NotifyArgs> out = {};
- float xCursorPosition, yCursorPosition;
- mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
+
+ const auto [xCursorPosition, yCursorPosition] = mPointerController->getPosition();
if (mCurrentClassification != MotionClassification::MULTI_FINGER_SWIPE) {
// If the user changes the number of fingers mid-way through a swipe (e.g. they start with
// three and then put a fourth finger down), the gesture library will treat it as two
@@ -292,8 +294,6 @@
yCursorPosition));
}
}
- // TODO(b/251196347): Set the gesture properties appropriately to avoid needing to negate the Y
- // values.
float rotatedDeltaX = dx, rotatedDeltaY = -dy;
rotateDelta(mOrientation, &rotatedDeltaX, &rotatedDeltaY);
for (size_t i = 0; i < mSwipeFingerCount; i++) {
@@ -304,8 +304,6 @@
coords.getAxisValue(AMOTION_EVENT_AXIS_Y) + rotatedDeltaY);
}
float xOffset = dx / (mXAxisInfo.maxValue - mXAxisInfo.minValue);
- // TODO(b/251196347): Set the gesture properties appropriately to avoid needing to negate the Y
- // values.
float yOffset = -dy / (mYAxisInfo.maxValue - mYAxisInfo.minValue);
mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_GESTURE_X_OFFSET, xOffset);
mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_GESTURE_Y_OFFSET, yOffset);
@@ -322,8 +320,7 @@
if (mCurrentClassification != MotionClassification::MULTI_FINGER_SWIPE) {
return out;
}
- float xCursorPosition, yCursorPosition;
- mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
+ const auto [xCursorPosition, yCursorPosition] = mPointerController->getPosition();
mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_GESTURE_X_OFFSET, 0);
mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_GESTURE_Y_OFFSET, 0);
@@ -347,8 +344,8 @@
[[nodiscard]] std::list<NotifyArgs> GestureConverter::handlePinch(nsecs_t when, nsecs_t readTime,
const Gesture& gesture) {
std::list<NotifyArgs> out;
- float xCursorPosition, yCursorPosition;
- mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
+
+ const auto [xCursorPosition, yCursorPosition] = mPointerController->getPosition();
// Pinch gesture phases are reported a little differently from others, in that the same details
// struct is used for all phases of the gesture, just with different zoom_state values. When
diff --git a/services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp b/services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp
index 3d88338..be2bfed 100644
--- a/services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp
+++ b/services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp
@@ -19,6 +19,7 @@
#include "gestures/PropertyProvider.h"
#include <algorithm>
+#include <optional>
#include <utility>
#include <android-base/stringprintf.h>
@@ -255,36 +256,34 @@
bool parsedSuccessfully = false;
Visitor setVisitor{
[&](int*) {
- int32_t value;
- parsedSuccessfully = idcProperties.tryGetProperty(propertyName, value);
- if (parsedSuccessfully) {
- setIntValues({value});
+ if (std::optional<int32_t> value = idcProperties.getInt(propertyName); value) {
+ parsedSuccessfully = true;
+ setIntValues({*value});
}
},
[&](GesturesPropBool*) {
- bool value;
- parsedSuccessfully = idcProperties.tryGetProperty(propertyName, value);
- if (parsedSuccessfully) {
- setBoolValues({value});
+ if (std::optional<bool> value = idcProperties.getBool(propertyName); value) {
+ parsedSuccessfully = true;
+ setBoolValues({*value});
}
},
[&](double*) {
- double value;
- parsedSuccessfully = idcProperties.tryGetProperty(propertyName, value);
- if (parsedSuccessfully) {
- setRealValues({value});
+ if (std::optional<double> value = idcProperties.getDouble(propertyName); value) {
+ parsedSuccessfully = true;
+ setRealValues({*value});
}
},
[&](const char**) {
ALOGE("Gesture property \"%s\" is a string, and so cannot be set in an IDC file.",
mName.c_str());
+ // We've already reported the type mismatch, so set parsedSuccessfully.
+ parsedSuccessfully = true;
},
};
std::visit(setVisitor, mDataPointer);
- ALOGE_IF(!parsedSuccessfully, "Gesture property \"%s\" could set due to a type mismatch.",
+ ALOGE_IF(!parsedSuccessfully, "Gesture property \"%s\" couldn't be set due to a type mismatch.",
mName.c_str());
- return;
}
template <typename T, typename U>
diff --git a/services/inputflinger/tests/FakePointerController.cpp b/services/inputflinger/tests/FakePointerController.cpp
index 28dad95..ad311f9 100644
--- a/services/inputflinger/tests/FakePointerController.cpp
+++ b/services/inputflinger/tests/FakePointerController.cpp
@@ -45,9 +45,8 @@
return mButtonState;
}
-void FakePointerController::getPosition(float* outX, float* outY) const {
- *outX = mX;
- *outY = mY;
+FloatPoint FakePointerController::getPosition() const {
+ return {mX, mY};
}
int32_t FakePointerController::getDisplayId() const {
@@ -59,8 +58,7 @@
}
void FakePointerController::assertPosition(float x, float y) {
- float actualX, actualY;
- getPosition(&actualX, &actualY);
+ const auto [actualX, actualY] = getPosition();
ASSERT_NEAR(x, actualX, 1);
ASSERT_NEAR(y, actualY, 1);
}
@@ -69,13 +67,8 @@
return mIsPointerShown;
}
-bool FakePointerController::getBounds(float* outMinX, float* outMinY, float* outMaxX,
- float* outMaxY) const {
- *outMinX = mMinX;
- *outMinY = mMinY;
- *outMaxX = mMaxX;
- *outMaxY = mMaxY;
- return mHaveBounds;
+std::optional<FloatRect> FakePointerController::getBounds() const {
+ return mHaveBounds ? std::make_optional<FloatRect>(mMinX, mMinY, mMaxX, mMaxY) : std::nullopt;
}
void FakePointerController::move(float deltaX, float deltaY) {
diff --git a/services/inputflinger/tests/FakePointerController.h b/services/inputflinger/tests/FakePointerController.h
index dd56e65..6d7bbeb 100644
--- a/services/inputflinger/tests/FakePointerController.h
+++ b/services/inputflinger/tests/FakePointerController.h
@@ -34,7 +34,7 @@
void setPosition(float x, float y) override;
void setButtonState(int32_t buttonState) override;
int32_t getButtonState() const override;
- void getPosition(float* outX, float* outY) const override;
+ FloatPoint getPosition() const override;
int32_t getDisplayId() const override;
void setDisplayViewport(const DisplayViewport& viewport) override;
@@ -42,7 +42,7 @@
bool isPointerShown();
private:
- bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const override;
+ std::optional<FloatRect> getBounds() const override;
void move(float deltaX, float deltaY) override;
void fade(Transition) override;
void unfade(Transition) override;
diff --git a/services/inputflinger/tests/GestureConverter_test.cpp b/services/inputflinger/tests/GestureConverter_test.cpp
index 9c624ba..bbf7e8e 100644
--- a/services/inputflinger/tests/GestureConverter_test.cpp
+++ b/services/inputflinger/tests/GestureConverter_test.cpp
@@ -252,14 +252,16 @@
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithCoords(POINTER_X, POINTER_Y),
WithGestureScrollDistance(0, 0, EPSILON),
WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE),
- WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER), WithDownTime(downTime)));
+ WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER), WithDownTime(downTime),
+ WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE)));
args.pop_front();
ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()),
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
WithCoords(POINTER_X, POINTER_Y - 10),
WithGestureScrollDistance(0, 10, EPSILON),
WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE),
- WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER)));
+ WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER),
+ WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE)));
Gesture continueGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -5);
args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, continueGesture);
@@ -269,7 +271,8 @@
WithCoords(POINTER_X, POINTER_Y - 15),
WithGestureScrollDistance(0, 5, EPSILON),
WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE),
- WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER)));
+ WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER),
+ WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE)));
Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 1, 1,
GESTURES_FLING_START);
@@ -280,7 +283,8 @@
WithCoords(POINTER_X, POINTER_Y - 15),
WithGestureScrollDistance(0, 0, EPSILON),
WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE),
- WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER)));
+ WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER),
+ WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE)));
}
TEST_F(GestureConverterTest, Scroll_Rotated) {
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index e4ba241..e299643 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -230,10 +230,10 @@
const auto& motionEvent = static_cast<const MotionEvent&>(event);
EXPECT_EQ(motionEvent.getEventTime(), args.eventTime);
EXPECT_EQ(motionEvent.getAction(), args.action);
- EXPECT_EQ(motionEvent.getX(0), point.x);
- EXPECT_EQ(motionEvent.getY(0), point.y);
- EXPECT_EQ(motionEvent.getRawX(0), point.x);
- EXPECT_EQ(motionEvent.getRawY(0), point.y);
+ EXPECT_NEAR(motionEvent.getX(0), point.x, MotionEvent::ROUNDING_PRECISION);
+ EXPECT_NEAR(motionEvent.getY(0), point.y, MotionEvent::ROUNDING_PRECISION);
+ EXPECT_NEAR(motionEvent.getRawX(0), point.x, MotionEvent::ROUNDING_PRECISION);
+ EXPECT_NEAR(motionEvent.getRawY(0), point.y, MotionEvent::ROUNDING_PRECISION);
});
}
@@ -3938,8 +3938,7 @@
public:
void SetUp() override {
InputDispatcherTest::SetUp();
- mDisplayInfos.clear();
- mWindowInfos.clear();
+ removeAllWindowsAndDisplays();
}
void addDisplayInfo(int displayId, const ui::Transform& transform) {
@@ -3955,6 +3954,11 @@
mDispatcher->onWindowInfosChanged(mWindowInfos, mDisplayInfos);
}
+ void removeAllWindowsAndDisplays() {
+ mDisplayInfos.clear();
+ mWindowInfos.clear();
+ }
+
// Set up a test scenario where the display has a scaled projection and there are two windows
// on the display.
std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupScaledDisplayScenario() {
@@ -3987,11 +3991,11 @@
std::vector<gui::WindowInfo> mWindowInfos;
};
-TEST_F(InputDispatcherDisplayProjectionTest, HitTestsInDisplaySpace) {
+TEST_F(InputDispatcherDisplayProjectionTest, HitTestCoordinateSpaceConsistency) {
auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
// Send down to the first window. The point is represented in the display space. The point is
- // selected so that if the hit test was done with the transform applied to it, then it would
- // end up in the incorrect window.
+ // selected so that if the hit test was performed with the point and the bounds being in
+ // different coordinate spaces, the event would end up in the incorrect window.
NotifyMotionArgs downMotionArgs =
generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
ADISPLAY_ID_DEFAULT, {PointF{75, 55}});
@@ -4066,6 +4070,81 @@
EXPECT_EQ(80, event->getY(0));
}
+/** Ensure consistent behavior of InputDispatcher in all orientations. */
+class InputDispatcherDisplayOrientationFixture
+ : public InputDispatcherDisplayProjectionTest,
+ public ::testing::WithParamInterface<ui::Rotation> {};
+
+// This test verifies the touchable region of a window for all rotations of the display by tapping
+// in different locations on the display, specifically points close to the four corners of a
+// window.
+TEST_P(InputDispatcherDisplayOrientationFixture, HitTestInDifferentOrientations) {
+ constexpr static int32_t displayWidth = 400;
+ constexpr static int32_t displayHeight = 800;
+
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+
+ const auto rotation = GetParam();
+
+ // Set up the display with the specified rotation.
+ const bool isRotated = rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270;
+ const int32_t logicalDisplayWidth = isRotated ? displayHeight : displayWidth;
+ const int32_t logicalDisplayHeight = isRotated ? displayWidth : displayHeight;
+ const ui::Transform displayTransform(ui::Transform::toRotationFlags(rotation),
+ logicalDisplayWidth, logicalDisplayHeight);
+ addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform);
+
+ // Create a window with its bounds determined in the logical display.
+ const Rect frameInLogicalDisplay(100, 100, 200, 300);
+ const Rect frameInDisplay = displayTransform.inverse().transform(frameInLogicalDisplay);
+ sp<FakeWindowHandle> window =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
+ window->setFrame(frameInDisplay, displayTransform);
+ addWindow(window);
+
+ // The following points in logical display space should be inside the window.
+ static const std::array<vec2, 4> insidePoints{
+ {{100, 100}, {199.99, 100}, {100, 299.99}, {199.99, 299.99}}};
+ for (const auto pointInsideWindow : insidePoints) {
+ const vec2 p = displayTransform.inverse().transform(pointInsideWindow);
+ const PointF pointInDisplaySpace{p.x, p.y};
+ const auto down = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {pointInDisplaySpace});
+ mDispatcher->notifyMotion(&down);
+ window->consumeMotionDown();
+
+ const auto up = generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {pointInDisplaySpace});
+ mDispatcher->notifyMotion(&up);
+ window->consumeMotionUp();
+ }
+
+ // The following points in logical display space should be outside the window.
+ static const std::array<vec2, 5> outsidePoints{
+ {{200, 100}, {100, 300}, {200, 300}, {100, 99.99}, {99.99, 100}}};
+ for (const auto pointOutsideWindow : outsidePoints) {
+ const vec2 p = displayTransform.inverse().transform(pointOutsideWindow);
+ const PointF pointInDisplaySpace{p.x, p.y};
+ const auto down = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {pointInDisplaySpace});
+ mDispatcher->notifyMotion(&down);
+
+ const auto up = generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {pointInDisplaySpace});
+ mDispatcher->notifyMotion(&up);
+ }
+ window->assertNoEvents();
+}
+
+// Run the precision tests for all rotations.
+INSTANTIATE_TEST_SUITE_P(InputDispatcherDisplayOrientationTests,
+ InputDispatcherDisplayOrientationFixture,
+ ::testing::Values(ui::ROTATION_0, ui::ROTATION_90, ui::ROTATION_180,
+ ui::ROTATION_270),
+ [](const testing::TestParamInfo<ui::Rotation>& testParamInfo) {
+ return ftl::enum_string(testParamInfo.param);
+ });
+
using TransferFunction = std::function<bool(const std::unique_ptr<InputDispatcher>& dispatcher,
sp<IBinder>, sp<IBinder>)>;
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 9732e8d..cdd2439 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -16,6 +16,7 @@
#include <cinttypes>
#include <memory>
+#include <optional>
#include <CursorInputMapper.h>
#include <InputDevice.h>
@@ -1830,7 +1831,7 @@
::testing::Types<UinputTouchScreen, UinputExternalStylus, UinputExternalStylusWithPressure>;
TYPED_TEST_SUITE(StylusButtonIntegrationTest, StylusButtonIntegrationTestTypes);
-TYPED_TEST(StylusButtonIntegrationTest, StylusButtonsGenerateKeyEvents) {
+TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsGenerateKeyEvents) {
const auto stylusId = TestFixture::mStylusInfo.getId();
TestFixture::mStylus->pressKey(BTN_STYLUS);
@@ -1844,7 +1845,7 @@
WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY), WithDeviceId(stylusId))));
}
-TYPED_TEST(StylusButtonIntegrationTest, StylusButtonsSurroundingTouchGesture) {
+TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsSurroundingTouchGesture) {
const Point centerPoint = TestFixture::mTouchscreen->getCenterPoint();
const auto touchscreenId = TestFixture::mTouchscreenInfo.getId();
const auto stylusId = TestFixture::mStylusInfo.getId();
@@ -1890,7 +1891,7 @@
WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY), WithDeviceId(stylusId))));
}
-TYPED_TEST(StylusButtonIntegrationTest, StylusButtonsSurroundingHoveringTouchGesture) {
+TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsSurroundingHoveringTouchGesture) {
const Point centerPoint = TestFixture::mTouchscreen->getCenterPoint();
const auto touchscreenId = TestFixture::mTouchscreenInfo.getId();
const auto stylusId = TestFixture::mStylusInfo.getId();
@@ -1966,7 +1967,7 @@
WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY), WithDeviceId(stylusId))));
}
-TYPED_TEST(StylusButtonIntegrationTest, StylusButtonsWithinTouchGesture) {
+TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsWithinTouchGesture) {
const Point centerPoint = TestFixture::mTouchscreen->getCenterPoint();
const auto touchscreenId = TestFixture::mTouchscreenInfo.getId();
const auto stylusId = TestFixture::mStylusInfo.getId();
@@ -2020,7 +2021,7 @@
WithDeviceId(touchscreenId))));
}
-TYPED_TEST(StylusButtonIntegrationTest, StylusButtonMotionEventsDisabled) {
+TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonMotionEventsDisabled) {
TestFixture::mFakePolicy->setStylusButtonMotionEventsEnabled(false);
TestFixture::mReader->requestRefreshConfiguration(
InputReaderConfiguration::CHANGE_STYLUS_BUTTON_REPORTING);
@@ -2077,7 +2078,7 @@
// ongoing stylus gesture that is being emitted by the touchscreen.
using ExternalStylusIntegrationTest = TouchIntegrationTest;
-TEST_F(ExternalStylusIntegrationTest, FusedExternalStylusPressureReported) {
+TEST_F(ExternalStylusIntegrationTest, DISABLED_FusedExternalStylusPressureReported) {
const Point centerPoint = mDevice->getCenterPoint();
// Create an external stylus capable of reporting pressure data that
@@ -2123,7 +2124,7 @@
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasNotCalled());
}
-TEST_F(ExternalStylusIntegrationTest, FusedExternalStylusPressureNotReported) {
+TEST_F(ExternalStylusIntegrationTest, DISABLED_FusedExternalStylusPressureNotReported) {
const Point centerPoint = mDevice->getCenterPoint();
// Create an external stylus capable of reporting pressure data that
@@ -2191,7 +2192,7 @@
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasNotCalled());
}
-TEST_F(ExternalStylusIntegrationTest, UnfusedExternalStylus) {
+TEST_F(ExternalStylusIntegrationTest, DISABLED_UnfusedExternalStylus) {
const Point centerPoint = mDevice->getCenterPoint();
// Create an external stylus device that does not support pressure. It should not affect any
@@ -2355,10 +2356,10 @@
InputReaderConfiguration config;
std::list<NotifyArgs> unused = mDevice->configure(ARBITRARY_TIME, &config, 0);
- std::string propertyValue;
- ASSERT_TRUE(mDevice->getConfiguration().tryGetProperty("key", propertyValue))
+ std::optional<std::string> propertyValue = mDevice->getConfiguration().getString("key");
+ ASSERT_TRUE(propertyValue.has_value())
<< "Device should have read configuration during configuration phase.";
- ASSERT_EQ("value", propertyValue);
+ ASSERT_EQ("value", *propertyValue);
ASSERT_NO_FATAL_FAILURE(mapper1.assertConfigureWasCalled());
ASSERT_NO_FATAL_FAILURE(mapper2.assertConfigureWasCalled());
@@ -6927,9 +6928,11 @@
// four times the resolution of the display in the Y axis.
prepareButtons();
mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_X, PRECISION_RAW_X_MIN, PRECISION_RAW_X_MAX,
- 0, 0);
+ PRECISION_RAW_X_FLAT, PRECISION_RAW_X_FUZZ,
+ PRECISION_RAW_X_RES);
mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_Y, PRECISION_RAW_Y_MIN, PRECISION_RAW_Y_MAX,
- 0, 0);
+ PRECISION_RAW_Y_FLAT, PRECISION_RAW_Y_FUZZ,
+ PRECISION_RAW_Y_RES);
}
static const int32_t PRECISION_RAW_X_MIN = TouchInputMapperTest::RAW_X_MIN;
@@ -6937,6 +6940,15 @@
static const int32_t PRECISION_RAW_Y_MIN = TouchInputMapperTest::RAW_Y_MIN;
static const int32_t PRECISION_RAW_Y_MAX = PRECISION_RAW_Y_MIN + DISPLAY_HEIGHT * 4 - 1;
+ static const int32_t PRECISION_RAW_X_RES = 50; // units per millimeter
+ static const int32_t PRECISION_RAW_Y_RES = 100; // units per millimeter
+
+ static const int32_t PRECISION_RAW_X_FLAT = 16;
+ static const int32_t PRECISION_RAW_Y_FLAT = 32;
+
+ static const int32_t PRECISION_RAW_X_FUZZ = 4;
+ static const int32_t PRECISION_RAW_Y_FUZZ = 8;
+
static const std::array<Point, 4> kRawCorners;
};
@@ -7094,6 +7106,41 @@
}
}
+TEST_P(TouchscreenPrecisionTestsFixture, MotionRangesAreOrientedInRotatedDisplay) {
+ const ui::Rotation displayRotation = GetParam();
+
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareDisplay(displayRotation);
+
+ __attribute__((unused)) SingleTouchInputMapper& mapper =
+ addMapperAndConfigure<SingleTouchInputMapper>();
+
+ const InputDeviceInfo deviceInfo = mDevice->getDeviceInfo();
+ // MotionRanges use display pixels as their units
+ const auto* xRange = deviceInfo.getMotionRange(AMOTION_EVENT_AXIS_X, AINPUT_SOURCE_TOUCHSCREEN);
+ const auto* yRange = deviceInfo.getMotionRange(AMOTION_EVENT_AXIS_Y, AINPUT_SOURCE_TOUCHSCREEN);
+
+ // The MotionRanges should be oriented in the rotated display's coordinate space
+ const bool displayRotated =
+ displayRotation == ui::ROTATION_90 || displayRotation == ui::ROTATION_270;
+
+ constexpr float MAX_X = 479.5;
+ constexpr float MAX_Y = 799.75;
+ EXPECT_EQ(xRange->min, 0.f);
+ EXPECT_EQ(yRange->min, 0.f);
+ EXPECT_EQ(xRange->max, displayRotated ? MAX_Y : MAX_X);
+ EXPECT_EQ(yRange->max, displayRotated ? MAX_X : MAX_Y);
+
+ EXPECT_EQ(xRange->flat, 8.f);
+ EXPECT_EQ(yRange->flat, 8.f);
+
+ EXPECT_EQ(xRange->fuzz, 2.f);
+ EXPECT_EQ(yRange->fuzz, 2.f);
+
+ EXPECT_EQ(xRange->resolution, 25.f); // pixels per millimeter
+ EXPECT_EQ(yRange->resolution, 25.f); // pixels per millimeter
+}
+
// Run the precision tests for all rotations.
INSTANTIATE_TEST_SUITE_P(TouchscreenPrecisionTests, TouchscreenPrecisionTestsFixture,
::testing::Values(ui::ROTATION_0, ui::ROTATION_90, ui::ROTATION_180,
diff --git a/services/inputflinger/tests/TestInputListenerMatchers.h b/services/inputflinger/tests/TestInputListenerMatchers.h
index edd14f8..09f7ae8 100644
--- a/services/inputflinger/tests/TestInputListenerMatchers.h
+++ b/services/inputflinger/tests/TestInputListenerMatchers.h
@@ -145,7 +145,7 @@
MATCHER_P(WithFlags, flags, "InputEvent with specified flags") {
*result_listener << "expected flags " << flags << ", but got " << arg.flags;
- return arg.flags == flags;
+ return arg.flags == static_cast<int32_t>(flags);
}
MATCHER_P(WithMotionClassification, classification,
diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h
index 546121d..5d7bf4b 100644
--- a/services/inputflinger/tests/fuzzers/MapperHelpers.h
+++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h
@@ -225,14 +225,23 @@
public:
FuzzPointerController(std::shared_ptr<ThreadSafeFuzzedDataProvider> mFdp) : mFdp(mFdp) {}
~FuzzPointerController() {}
- bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const override {
- return mFdp->ConsumeBool();
+ std::optional<FloatRect> getBounds() const override {
+ if (mFdp->ConsumeBool()) {
+ return {};
+ } else {
+ return FloatRect{mFdp->ConsumeFloatingPoint<float>(),
+ mFdp->ConsumeFloatingPoint<float>(),
+ mFdp->ConsumeFloatingPoint<float>(),
+ mFdp->ConsumeFloatingPoint<float>()};
+ }
}
void move(float deltaX, float deltaY) override {}
void setButtonState(int32_t buttonState) override {}
int32_t getButtonState() const override { return mFdp->ConsumeIntegral<int32_t>(); }
void setPosition(float x, float y) override {}
- void getPosition(float* outX, float* outY) const override {}
+ FloatPoint getPosition() const override {
+ return {mFdp->ConsumeFloatingPoint<float>(), mFdp->ConsumeFloatingPoint<float>()};
+ }
void fade(Transition transition) override {}
void unfade(Transition transition) override {}
void setPresentation(Presentation presentation) override {}
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 3cdb3d5..064bbd2 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -167,6 +167,7 @@
.receivesInput = receivesInput(),
.isSecure = isSecure(),
.isPrimary = isPrimary(),
+ .isVirtual = isVirtual(),
.rotationFlags = ui::Transform::toRotationFlags(mOrientation),
.transformHint = getTransformHint()};
}
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 925f111..ded734e 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -885,15 +885,17 @@
void FrameTimeline::DisplayFrame::classifyJank(nsecs_t& deadlineDelta, nsecs_t& deltaToVsync,
nsecs_t previousPresentTime) {
- if (mPredictionState == PredictionState::Expired ||
- mSurfaceFlingerActuals.presentTime == Fence::SIGNAL_TIME_INVALID) {
+ const bool presentTimeValid =
+ mSurfaceFlingerActuals.presentTime >= mSurfaceFlingerActuals.startTime;
+ if (mPredictionState == PredictionState::Expired || !presentTimeValid) {
// Cannot do jank classification with expired predictions or invalid signal times. Set the
// deltas to 0 as both negative and positive deltas are used as real values.
mJankType = JankType::Unknown;
deadlineDelta = 0;
deltaToVsync = 0;
- if (mSurfaceFlingerActuals.presentTime == Fence::SIGNAL_TIME_INVALID) {
+ if (!presentTimeValid) {
mSurfaceFlingerActuals.presentTime = mSurfaceFlingerActuals.endTime;
+ mJankType |= JankType::DisplayHAL;
}
return;
diff --git a/services/surfaceflinger/FrontEnd/DisplayInfo.h b/services/surfaceflinger/FrontEnd/DisplayInfo.h
index 6b9d7a2..76b36fe 100644
--- a/services/surfaceflinger/FrontEnd/DisplayInfo.h
+++ b/services/surfaceflinger/FrontEnd/DisplayInfo.h
@@ -30,6 +30,7 @@
bool isSecure;
// TODO(b/238781169) can eliminate once sPrimaryDisplayRotationFlags is removed.
bool isPrimary;
+ bool isVirtual;
ui::Transform::RotationFlags rotationFlags;
ui::Transform::RotationFlags transformHint;
std::string getDebugString() const {
diff --git a/services/surfaceflinger/FrontEnd/LayerCreationArgs.cpp b/services/surfaceflinger/FrontEnd/LayerCreationArgs.cpp
index 6659825..ce21233 100644
--- a/services/surfaceflinger/FrontEnd/LayerCreationArgs.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerCreationArgs.cpp
@@ -65,7 +65,13 @@
}
}
-LayerCreationArgs::LayerCreationArgs(const LayerCreationArgs& args)
- : LayerCreationArgs(args.flinger, args.client, args.name, args.flags, args.metadata) {}
+LayerCreationArgs::LayerCreationArgs(std::optional<uint32_t> id, bool internalLayer)
+ : LayerCreationArgs(nullptr, nullptr, /*name=*/"", /*flags=*/0, /*metadata=*/{}, id,
+ internalLayer) {}
+
+LayerCreationArgs LayerCreationArgs::fromOtherArgs(const LayerCreationArgs& other) {
+ // returns a new instance of LayerCreationArgs with a unique id.
+ return LayerCreationArgs(other.flinger, other.client, other.name, other.flags, other.metadata);
+}
} // namespace android::surfaceflinger
diff --git a/services/surfaceflinger/FrontEnd/LayerCreationArgs.h b/services/surfaceflinger/FrontEnd/LayerCreationArgs.h
index 2cd6b55..011250c 100644
--- a/services/surfaceflinger/FrontEnd/LayerCreationArgs.h
+++ b/services/surfaceflinger/FrontEnd/LayerCreationArgs.h
@@ -37,11 +37,13 @@
struct LayerCreationArgs {
static std::atomic<uint32_t> sSequence;
static uint32_t getInternalLayerId(uint32_t id);
+ static LayerCreationArgs fromOtherArgs(const LayerCreationArgs& other);
LayerCreationArgs(android::SurfaceFlinger*, sp<android::Client>, std::string name,
uint32_t flags, gui::LayerMetadata, std::optional<uint32_t> id = std::nullopt,
bool internalLayer = false);
- LayerCreationArgs(const LayerCreationArgs&);
+ LayerCreationArgs(std::optional<uint32_t> id, bool internalLayer = false);
+ LayerCreationArgs() = default; // for tracing
android::SurfaceFlinger* flinger;
sp<android::Client> client;
@@ -56,6 +58,8 @@
wp<IBinder> parentHandle = nullptr;
wp<IBinder> mirrorLayerHandle = nullptr;
ui::LayerStack layerStackToMirror = ui::INVALID_LAYER_STACK;
+ uint32_t parentId = UNASSIGNED_LAYER_ID;
+ uint32_t layerIdToMirror = UNASSIGNED_LAYER_ID;
};
} // namespace android::surfaceflinger
diff --git a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp
index 33cc429..3706225 100644
--- a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp
@@ -20,8 +20,7 @@
#define LOG_TAG "LayerLifecycleManager"
#include "LayerLifecycleManager.h"
-#include "Layer.h" // temporarily needed for LayerHandle
-#include "LayerHandle.h"
+#include "Client.h" // temporarily needed for LayerCreationArgs
#include "LayerLog.h"
#include "SwapErase.h"
@@ -72,12 +71,14 @@
}
}
-void LayerLifecycleManager::onHandlesDestroyed(const std::vector<uint32_t>& destroyedHandles) {
+void LayerLifecycleManager::onHandlesDestroyed(const std::vector<uint32_t>& destroyedHandles,
+ bool ignoreUnknownHandles) {
std::vector<uint32_t> layersToBeDestroyed;
for (const auto& layerId : destroyedHandles) {
auto it = mIdToLayer.find(layerId);
if (it == mIdToLayer.end()) {
- LOG_ALWAYS_FATAL("%s Layerid not found %d", __func__, layerId);
+ LOG_ALWAYS_FATAL_IF(!ignoreUnknownHandles, "%s Layerid not found %d", __func__,
+ layerId);
continue;
}
RequestedLayerState& layer = it->second.owner;
@@ -167,7 +168,7 @@
for (const auto& transaction : transactions) {
for (const auto& resolvedComposerState : transaction.states) {
const auto& clientState = resolvedComposerState.state;
- uint32_t layerId = LayerHandle::getLayerId(clientState.surface);
+ uint32_t layerId = resolvedComposerState.layerId;
if (layerId == UNASSIGNED_LAYER_ID) {
ALOGW("%s Handle %p is not valid", __func__, clientState.surface.get());
continue;
@@ -175,15 +176,14 @@
RequestedLayerState* layer = getLayerFromId(layerId);
if (layer == nullptr) {
- LOG_ALWAYS_FATAL("%s Layer with handle %p (layerid=%d) not found", __func__,
- clientState.surface.get(), layerId);
+ LOG_ALWAYS_FATAL("%s Layer with layerid=%d not found", __func__, layerId);
continue;
}
if (!layer->handleAlive) {
- LOG_ALWAYS_FATAL("%s Layer's handle %p (layerid=%d) is not alive. Possible out of "
+ LOG_ALWAYS_FATAL("%s Layer's with layerid=%d) is not alive. Possible out of "
"order LayerLifecycleManager updates",
- __func__, clientState.surface.get(), layerId);
+ __func__, layerId);
continue;
}
@@ -198,13 +198,11 @@
if (layer->what & layer_state_t::eBackgroundColorChanged) {
if (layer->bgColorLayerId == UNASSIGNED_LAYER_ID && layer->bgColor.a != 0) {
- LayerCreationArgs backgroundLayerArgs{nullptr,
- nullptr,
- layer->name + "BackgroundColorLayer",
- ISurfaceComposerClient::eFXSurfaceEffect,
- {},
- layer->id,
- /*internalLayer=*/true};
+ LayerCreationArgs backgroundLayerArgs(layer->id,
+ /*internalLayer=*/true);
+ backgroundLayerArgs.parentId = layer->id;
+ backgroundLayerArgs.name = layer->name + "BackgroundColorLayer";
+ backgroundLayerArgs.flags = ISurfaceComposerClient::eFXSurfaceEffect;
std::vector<std::unique_ptr<RequestedLayerState>> newLayers;
newLayers.emplace_back(
std::make_unique<RequestedLayerState>(backgroundLayerArgs));
diff --git a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h
index 25d27ee..3d9a74c 100644
--- a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h
+++ b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h
@@ -40,7 +40,10 @@
// External state changes should be updated in the following order:
void addLayers(std::vector<std::unique_ptr<RequestedLayerState>>);
void applyTransactions(const std::vector<TransactionState>&);
- void onHandlesDestroyed(const std::vector<uint32_t>&);
+ // Ignore unknown handles when iteroping with legacy front end. In the old world, we
+ // would create child layers which are not necessary with the new front end. This means
+ // we will get notified for handle changes that don't exist in the new front end.
+ void onHandlesDestroyed(const std::vector<uint32_t>&, bool ignoreUnknownHandles = false);
// Detaches the layer from its relative parent to prevent a loop in the
// layer hierarchy. This overrides the RequestedLayerState and leaves
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
index e2cbe28..a5fdaf4 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
@@ -24,7 +24,6 @@
#include "Layer.h"
#include "LayerCreationArgs.h"
-#include "LayerHandle.h"
#include "LayerLog.h"
#include "RequestedLayerState.h"
@@ -33,14 +32,6 @@
using namespace ftl::flag_operators;
namespace {
-uint32_t getLayerIdFromSurfaceControl(sp<SurfaceControl> surfaceControl) {
- if (!surfaceControl) {
- return UNASSIGNED_LAYER_ID;
- }
-
- return LayerHandle::getLayerId(surfaceControl->getHandle());
-}
-
std::string layerIdToString(uint32_t layerId) {
return layerId == UNASSIGNED_LAYER_ID ? "none" : std::to_string(layerId);
}
@@ -64,17 +55,17 @@
layerCreationFlags(args.flags),
textureName(args.textureName),
ownerUid(args.ownerUid),
- ownerPid(args.ownerPid) {
+ ownerPid(args.ownerPid),
+ parentId(args.parentId),
+ layerIdToMirror(args.layerIdToMirror) {
layerId = static_cast<int32_t>(args.sequence);
changes |= RequestedLayerState::Changes::Created;
metadata.merge(args.metadata);
changes |= RequestedLayerState::Changes::Metadata;
handleAlive = true;
- parentId = LayerHandle::getLayerId(args.parentHandle.promote());
- if (args.parentHandle != nullptr) {
+ if (parentId != UNASSIGNED_LAYER_ID) {
canBeRoot = false;
}
- layerIdToMirror = LayerHandle::getLayerId(args.mirrorLayerHandle.promote());
if (layerIdToMirror != UNASSIGNED_LAYER_ID) {
changes |= RequestedLayerState::Changes::Mirror;
} else if (args.layerStackToMirror != ui::INVALID_LAYER_STACK) {
@@ -209,7 +200,7 @@
}
if (clientState.what & layer_state_t::eReparent) {
changes |= RequestedLayerState::Changes::Parent;
- parentId = getLayerIdFromSurfaceControl(clientState.parentSurfaceControlForChild);
+ parentId = resolvedComposerState.parentId;
parentSurfaceControlForChild = nullptr;
// Once a layer has be reparented, it cannot be placed at the root. It sounds odd
// but thats the existing logic and until we make this behavior more explicit, we need
@@ -218,7 +209,7 @@
}
if (clientState.what & layer_state_t::eRelativeLayerChanged) {
changes |= RequestedLayerState::Changes::RelativeParent;
- relativeParentId = getLayerIdFromSurfaceControl(clientState.relativeLayerSurfaceControl);
+ relativeParentId = resolvedComposerState.relativeParentId;
isRelativeOf = true;
relativeLayerSurfaceControl = nullptr;
}
@@ -235,10 +226,8 @@
changes |= RequestedLayerState::Changes::RelativeParent;
}
if (clientState.what & layer_state_t::eInputInfoChanged) {
- wp<IBinder>& touchableRegionCropHandle =
- windowInfoHandle->editInfo()->touchableRegionCropHandle;
- touchCropId = LayerHandle::getLayerId(touchableRegionCropHandle.promote());
- touchableRegionCropHandle.clear();
+ touchCropId = resolvedComposerState.touchCropId;
+ windowInfoHandle->editInfo()->touchableRegionCropHandle.clear();
}
if (clientState.what & layer_state_t::eStretchChanged) {
stretchEffect.sanitize();
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.h b/services/surfaceflinger/FrontEnd/RequestedLayerState.h
index 6f5485d..216e95f 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.h
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.h
@@ -105,17 +105,17 @@
std::shared_ptr<renderengine::ExternalTexture> externalTexture;
gui::GameMode gameMode;
scheduler::LayerInfo::FrameRate requestedFrameRate;
- ui::LayerStack layerStackToMirror = ui::INVALID_LAYER_STACK;
+ uint32_t parentId = UNASSIGNED_LAYER_ID;
+ uint32_t relativeParentId = UNASSIGNED_LAYER_ID;
uint32_t layerIdToMirror = UNASSIGNED_LAYER_ID;
+ ui::LayerStack layerStackToMirror = ui::INVALID_LAYER_STACK;
+ uint32_t touchCropId = UNASSIGNED_LAYER_ID;
+ uint32_t bgColorLayerId = UNASSIGNED_LAYER_ID;
// book keeping states
bool handleAlive = true;
bool isRelativeOf = false;
- uint32_t parentId = UNASSIGNED_LAYER_ID;
- uint32_t relativeParentId = UNASSIGNED_LAYER_ID;
std::vector<uint32_t> mirrorIds{};
- uint32_t touchCropId = UNASSIGNED_LAYER_ID;
- uint32_t bgColorLayerId = UNASSIGNED_LAYER_ID;
ftl::Flags<RequestedLayerState::Changes> changes;
bool bgColorLayer = false;
};
diff --git a/services/surfaceflinger/FrontEnd/Update.h b/services/surfaceflinger/FrontEnd/Update.h
new file mode 100644
index 0000000..e1449b6
--- /dev/null
+++ b/services/surfaceflinger/FrontEnd/Update.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gui/DisplayInfo.h>
+
+#include "FrontEnd/LayerCreationArgs.h"
+#include "RequestedLayerState.h"
+#include "TransactionState.h"
+
+namespace android {
+struct LayerCreatedState {
+ LayerCreatedState(const wp<Layer>& layer, const wp<Layer>& parent, bool addToRoot)
+ : layer(layer), initialParent(parent), addToRoot(addToRoot) {}
+ wp<Layer> layer;
+ // Indicates the initial parent of the created layer, only used for creating layer in
+ // SurfaceFlinger. If nullptr, it may add the created layer into the current root layers.
+ wp<Layer> initialParent;
+ // Indicates whether the layer getting created should be added at root if there's no parent
+ // and has permission ACCESS_SURFACE_FLINGER. If set to false and no parent, the layer will
+ // be added offscreen.
+ bool addToRoot;
+};
+} // namespace android
+
+namespace android::surfaceflinger::frontend {
+
+// Atomic set of changes affecting layer state. These changes are queued in binder threads and
+// applied every vsync.
+struct Update {
+ std::vector<TransactionState> transactions;
+ std::vector<LayerCreatedState> layerCreatedStates;
+ std::vector<std::unique_ptr<frontend::RequestedLayerState>> newLayers;
+ std::vector<LayerCreationArgs> layerCreationArgs;
+ std::vector<uint32_t> destroyedHandles;
+};
+
+} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/HdrLayerInfoReporter.cpp b/services/surfaceflinger/HdrLayerInfoReporter.cpp
index c88554e..9eefbe4 100644
--- a/services/surfaceflinger/HdrLayerInfoReporter.cpp
+++ b/services/surfaceflinger/HdrLayerInfoReporter.cpp
@@ -40,7 +40,8 @@
for (const auto& listener : toInvoke) {
ATRACE_NAME("invoking onHdrLayerInfoChanged");
- listener->onHdrLayerInfoChanged(info.numberOfHdrLayers, info.maxW, info.maxH, info.flags);
+ listener->onHdrLayerInfoChanged(info.numberOfHdrLayers, info.maxW, info.maxH, info.flags,
+ info.maxDesiredHdrSdrRatio);
}
}
diff --git a/services/surfaceflinger/HdrLayerInfoReporter.h b/services/surfaceflinger/HdrLayerInfoReporter.h
index 9b70c16..bf7c775 100644
--- a/services/surfaceflinger/HdrLayerInfoReporter.h
+++ b/services/surfaceflinger/HdrLayerInfoReporter.h
@@ -43,27 +43,18 @@
// With peak display brightnesses exceeding 1,000 nits currently, HLG's request could
// actually be satisfied in some ambient conditions such that limiting that max for that
// content in theory makes sense
- float maxDesiredSdrHdrRatio = 0.f;
+ float maxDesiredHdrSdrRatio = 0.f;
bool operator==(const HdrLayerInfo& other) const {
return numberOfHdrLayers == other.numberOfHdrLayers && maxW == other.maxW &&
- maxH == other.maxH && flags == other.flags;
+ maxH == other.maxH && flags == other.flags &&
+ maxDesiredHdrSdrRatio == other.maxDesiredHdrSdrRatio;
}
bool operator!=(const HdrLayerInfo& other) const { return !(*this == other); }
void mergeDesiredRatio(float update) {
- if (maxDesiredSdrHdrRatio == 0.f) {
- // If nothing is set, take the incoming value
- maxDesiredSdrHdrRatio = update;
- } else if (update == 1.f) {
- // If the request is to "go to max", then take it regardless
- maxDesiredSdrHdrRatio = 1.f;
- } else if (maxDesiredSdrHdrRatio != 1.f) {
- // If we're not currently asked to "go to max", then take the max
- // of the incoming requests
- maxDesiredSdrHdrRatio = std::max(maxDesiredSdrHdrRatio, update);
- }
+ maxDesiredHdrSdrRatio = std::max(maxDesiredHdrSdrRatio, update);
}
};
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 0f2af2f..9521371 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -3168,6 +3168,7 @@
}
bool Layer::setSurfaceDamageRegion(const Region& surfaceDamage) {
+ if (mDrawingState.surfaceDamageRegion.hasSameRects(surfaceDamage)) return false;
mDrawingState.surfaceDamageRegion = surfaceDamage;
mDrawingState.modified = true;
setTransactionFlags(eTransactionNeeded);
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 2fb122c..f7e1969 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -848,6 +848,11 @@
void updateMetadataSnapshot(const LayerMetadata& parentMetadata);
void updateRelativeMetadataSnapshot(const LayerMetadata& relativeLayerMetadata,
std::unordered_set<Layer*>& visited);
+ sp<Layer> getClonedFrom() const {
+ return mClonedFrom != nullptr ? mClonedFrom.promote() : nullptr;
+ }
+ bool isClone() { return mClonedFrom != nullptr; }
+
bool willPresentCurrentTransaction() const;
void callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener,
@@ -885,10 +890,6 @@
void gatherBufferInfo();
void onSurfaceFrameCreated(const std::shared_ptr<frametimeline::SurfaceFrame>&);
- sp<Layer> getClonedFrom() const {
- return mClonedFrom != nullptr ? mClonedFrom.promote() : nullptr;
- }
- bool isClone() { return mClonedFrom != nullptr; }
bool isClonedFromAlive() { return getClonedFrom() != nullptr; }
void cloneDrawingState(const Layer* from);
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index 55281fa..5c91b91 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -394,6 +394,22 @@
[&]() { return layerInfo->mutable_destination_frame(); });
}
+google::protobuf::RepeatedPtrField<DisplayProto> LayerProtoHelper::writeDisplayInfoToProto(
+ const display::DisplayMap<ui::LayerStack, frontend::DisplayInfo>& displayInfos) {
+ google::protobuf::RepeatedPtrField<DisplayProto> displays;
+ displays.Reserve(displayInfos.size());
+ for (const auto& [layerStack, displayInfo] : displayInfos) {
+ auto displayProto = displays.Add();
+ displayProto->set_id(displayInfo.info.displayId);
+ displayProto->set_layer_stack(layerStack.id);
+ displayProto->mutable_size()->set_w(displayInfo.info.logicalWidth);
+ displayProto->mutable_size()->set_h(displayInfo.info.logicalHeight);
+ writeTransformToProto(displayInfo.transform, displayProto->mutable_transform());
+ displayProto->set_is_virtual(displayInfo.isVirtual);
+ }
+ return displays;
+}
+
} // namespace surfaceflinger
} // namespace android
diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h
index de4bd01..38d73f6 100644
--- a/services/surfaceflinger/LayerProtoHelper.h
+++ b/services/surfaceflinger/LayerProtoHelper.h
@@ -63,10 +63,11 @@
const frontend::LayerSnapshotBuilder& snapshotBuilder,
const std::unordered_map<uint32_t, sp<Layer>>& mLegacyLayers,
uint32_t traceFlags);
-
static void writeSnapshotToProto(LayerProto* outProto,
const frontend::RequestedLayerState& requestedState,
const frontend::LayerSnapshot& snapshot, uint32_t traceFlags);
+ static google::protobuf::RepeatedPtrField<DisplayProto> writeDisplayInfoToProto(
+ const display::DisplayMap<ui::LayerStack, frontend::DisplayInfo>& displayInfos);
};
} // namespace surfaceflinger
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
index f6fe468..eec7c08 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
@@ -308,7 +308,7 @@
// significantly faster than the display rate, at it would cause a significant frame drop.
// It is more appropriate to choose a higher display rate even if
// a pull-down will be required.
- constexpr float kMinMultiplier = 0.25f;
+ constexpr float kMinMultiplier = 0.75f;
if (multiplier >= kMinMultiplier &&
isFractionalPairOrMultiple(refreshRate, layer.desiredRefreshRate)) {
return kScoreForFractionalPairs;
@@ -958,7 +958,7 @@
}
const bool ascending = (refreshRateOrder == RefreshRateOrder::Ascending);
- const auto id = frameRateMode.modePtr->getId();
+ const auto id = modePtr->getId();
if (ascending && frameRateMode.fps < *maxRenderRateForMode.get(id)) {
// TODO(b/266481656): Once this bug is fixed, we can remove this workaround and actually
// use a lower frame rate when we want Ascending frame rates.
@@ -970,14 +970,20 @@
if (ascending) {
score = 1.0f / score;
}
+
+ constexpr float kScore = std::numeric_limits<float>::max();
if (preferredDisplayModeOpt) {
if (*preferredDisplayModeOpt == modePtr->getId()) {
- constexpr float kScore = std::numeric_limits<float>::max();
ranking.emplace_front(ScoredFrameRate{frameRateMode, kScore});
return;
}
constexpr float kNonPreferredModePenalty = 0.95f;
score *= kNonPreferredModePenalty;
+ } else if (ascending && id == getMinRefreshRateByPolicyLocked()->getId()) {
+ // TODO(b/266481656): Once this bug is fixed, we can remove this workaround
+ // and actually use a lower frame rate when we want Ascending frame rates.
+ ranking.emplace_front(ScoredFrameRate{frameRateMode, kScore});
+ return;
}
ALOGV("%s(%s) %s (%s) scored %.2f", whence, ftl::enum_string(refreshRateOrder).c_str(),
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index f18dfdc..6e33272 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -402,6 +402,7 @@
}
void Scheduler::resyncAllToHardwareVsync(bool allowToEnable) {
+ ATRACE_CALL();
std::scoped_lock lock(mDisplayLock);
ftl::FakeGuard guard(kMainThreadContext);
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 62a5fb2..74547d5 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -165,7 +165,7 @@
void setDuration(ConnectionHandle, std::chrono::nanoseconds workDuration,
std::chrono::nanoseconds readyDuration);
- const VsyncModulator& vsyncModulator() const { return *mVsyncModulator; }
+ VsyncModulator& vsyncModulator() { return *mVsyncModulator; }
// In some cases, we should only modulate for the pacesetter display. In those
// cases, the caller should pass in the relevant display, and the method
diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.cpp b/services/surfaceflinger/Scheduler/VsyncModulator.cpp
index c9af4c2..586357f 100644
--- a/services/surfaceflinger/Scheduler/VsyncModulator.cpp
+++ b/services/surfaceflinger/Scheduler/VsyncModulator.cpp
@@ -187,9 +187,9 @@
static_cast<void>(updateVsyncConfigLocked());
}
-bool VsyncModulator::isVsyncConfigDefault() const {
+bool VsyncModulator::isVsyncConfigEarly() const {
std::lock_guard<std::mutex> lock(mMutex);
- return getNextVsyncConfigType() == VsyncConfigType::Late;
+ return getNextVsyncConfigType() != VsyncConfigType::Late;
}
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.h b/services/surfaceflinger/Scheduler/VsyncModulator.h
index dc4dafd..be0d334 100644
--- a/services/surfaceflinger/Scheduler/VsyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VsyncModulator.h
@@ -53,8 +53,12 @@
explicit VsyncModulator(const VsyncConfigSet&, Now = Clock::now);
+ bool isVsyncConfigEarly() const EXCLUDES(mMutex);
+
VsyncConfig getVsyncConfig() const EXCLUDES(mMutex);
+ void cancelRefreshRateChange() { mRefreshRateChangePending = false; }
+
[[nodiscard]] VsyncConfig setVsyncConfigSet(const VsyncConfigSet&) EXCLUDES(mMutex);
// Changes offsets in response to transaction flags or commit.
@@ -72,8 +76,6 @@
[[nodiscard]] VsyncConfigOpt onDisplayRefresh(bool usedGpuComposition);
- [[nodiscard]] bool isVsyncConfigDefault() const;
-
protected:
// Called from unit tests as well
void binderDied(const wp<IBinder>&) override EXCLUDES(mMutex);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 0bdede8..c9d17d5 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -105,6 +105,7 @@
#include <memory>
#include <mutex>
#include <optional>
+#include <string>
#include <type_traits>
#include <unordered_map>
#include <vector>
@@ -130,6 +131,7 @@
#include "FrameTracer/FrameTracer.h"
#include "FrontEnd/LayerCreationArgs.h"
#include "FrontEnd/LayerHandle.h"
+#include "FrontEnd/LayerLifecycleManager.h"
#include "FrontEnd/LayerSnapshot.h"
#include "HdrLayerInfoReporter.h"
#include "Layer.h"
@@ -292,6 +294,13 @@
displayHdrCapabilities.getDesiredMinLuminance()};
}
+uint32_t getLayerIdFromSurfaceControl(sp<SurfaceControl> surfaceControl) {
+ if (!surfaceControl) {
+ return UNASSIGNED_LAYER_ID;
+ }
+ return LayerHandle::getLayerId(surfaceControl->getHandle());
+}
+
} // namespace anonymous
// ---------------------------------------------------------------------------
@@ -497,14 +506,13 @@
// the window manager died on us. prepare its eulogy.
mBootFinished = false;
- // Sever the link to inputflinger since it's gone as well.
- static_cast<void>(mScheduler->schedule(
- [this] { mInputFlinger.clear(); }));
+ static_cast<void>(mScheduler->schedule([this]() FTL_FAKE_GUARD(kMainThreadContext) {
+ // Sever the link to inputflinger since it's gone as well.
+ mInputFlinger.clear();
- // restore initial conditions (default device unblank, etc)
- initializeDisplays();
+ initializeDisplays();
+ }));
- // restart the boot-animation
startBootAnim();
}
@@ -873,7 +881,9 @@
mDrawingState = mCurrentState;
onActiveDisplayChangedLocked(nullptr, *display);
- initializeDisplays();
+
+ static_cast<void>(mScheduler->schedule(
+ [this]() FTL_FAKE_GUARD(kMainThreadContext) { initializeDisplays(); }));
mPowerAdvisor->init();
@@ -2175,7 +2185,7 @@
}
}
-bool SurfaceFlinger::updateLayerSnapshotsLegacy(VsyncId vsyncId, LifecycleUpdate& update,
+bool SurfaceFlinger::updateLayerSnapshotsLegacy(VsyncId vsyncId, frontend::Update& update,
bool transactionsFlushed,
bool& outTransactionsAreEmpty) {
bool needsTraversal = false;
@@ -2227,7 +2237,7 @@
}
}
-bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, LifecycleUpdate& update,
+bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, frontend::Update& update,
bool transactionsFlushed, bool& outTransactionsAreEmpty) {
using Changes = frontend::RequestedLayerState::Changes;
ATRACE_NAME("updateLayerSnapshots");
@@ -2477,9 +2487,14 @@
Fps::fromPeriodNsecs(vsyncPeriod.ns()));
const bool flushTransactions = clearTransactionFlags(eTransactionFlushNeeded);
- LifecycleUpdate updates;
+ frontend::Update updates;
if (flushTransactions) {
updates = flushLifecycleUpdates();
+ if (mTransactionTracing) {
+ mTransactionTracing->addCommittedTransactions(vsyncId.value, frameTime.ns(),
+ updates, mFrontEndDisplayInfos,
+ mFrontEndDisplayInfosChanged);
+ }
}
bool transactionsAreEmpty;
if (mLegacyFrontEndEnabled) {
@@ -2521,7 +2536,7 @@
if (mLayerTracingEnabled && !mLayerTracing.flagIsSet(LayerTracing::TRACE_COMPOSITION)) {
// This will block and tracing should only be enabled for debugging.
- mLayerTracing.notify(mVisibleRegionsDirty, frameTime.ns(), vsyncId.value);
+ addToLayerTracing(mVisibleRegionsDirty, frameTime.ns(), vsyncId.value);
}
mLastCommittedVsyncId = vsyncId;
@@ -2626,7 +2641,9 @@
CompositionResult compositionResult{layerFE->stealCompositionResult()};
layer->onPreComposition(compositionResult.refreshStartTime);
for (auto releaseFence : compositionResult.releaseFences) {
- layer->onLayerDisplayed(releaseFence);
+ Layer* clonedFrom = layer->getClonedFrom().get();
+ auto owningLayer = clonedFrom ? clonedFrom : layer;
+ owningLayer->onLayerDisplayed(releaseFence);
}
if (compositionResult.lastClientCompositionFence) {
layer->setWasClientComposed(compositionResult.lastClientCompositionFence);
@@ -2692,7 +2709,7 @@
mLayersWithQueuedFrames.clear();
if (mLayerTracingEnabled && mLayerTracing.flagIsSet(LayerTracing::TRACE_COMPOSITION)) {
// This will block and should only be used for debugging.
- mLayerTracing.notify(mVisibleRegionsDirty, frameTime.ns(), vsyncId.value);
+ addToLayerTracing(mVisibleRegionsDirty, frameTime.ns(), vsyncId.value);
}
if (mVisibleRegionsDirty) mHdrLayerInfoChanged = true;
@@ -2882,7 +2899,12 @@
const auto* outputLayer =
compositionDisplay->getOutputLayerForLayer(layerFe);
if (outputLayer) {
- info.mergeDesiredRatio(snapshot.desiredSdrHdrRatio);
+ // TODO(b/267350616): Rename SdrHdrRatio -> HdrSdrRatio
+ // everywhere
+ const float desiredHdrSdrRatio = snapshot.desiredSdrHdrRatio <= 1.f
+ ? std::numeric_limits<float>::infinity()
+ : snapshot.desiredSdrHdrRatio;
+ info.mergeDesiredRatio(desiredHdrSdrRatio);
info.numberOfHdrLayers++;
const auto displayFrame = outputLayer->getState().displayFrame;
const int32_t area = displayFrame.width() * displayFrame.height();
@@ -3485,7 +3507,7 @@
// TODO(b/175678251) Call a listener instead.
if (currentState.physical->hwcDisplayId == getHwComposer().getPrimaryHwcDisplayId()) {
- updateActiveDisplayVsyncLocked(*display);
+ resetPhaseConfiguration(display->getActiveMode().fps);
}
}
return;
@@ -3519,9 +3541,11 @@
}
}
-void SurfaceFlinger::updateActiveDisplayVsyncLocked(const DisplayDevice& activeDisplay) {
+void SurfaceFlinger::resetPhaseConfiguration(Fps refreshRate) {
+ // Cancel the pending refresh rate change, if any, before updating the phase configuration.
+ mScheduler->vsyncModulator().cancelRefreshRateChange();
+
mVsyncConfiguration->reset();
- const Fps refreshRate = activeDisplay.getActiveMode().fps;
updatePhaseConfiguration(refreshRate);
mRefreshRateStats->setRefreshRate(refreshRate);
}
@@ -4061,7 +4085,7 @@
return !mLayersWithQueuedFrames.empty() && newDataLatched;
}
-status_t SurfaceFlinger::addClientLayer(const LayerCreationArgs& args, const sp<IBinder>& handle,
+status_t SurfaceFlinger::addClientLayer(LayerCreationArgs& args, const sp<IBinder>& handle,
const sp<Layer>& layer, const wp<Layer>& parent,
uint32_t* outTransformHint) {
if (mNumLayers >= MAX_LAYERS) {
@@ -4091,11 +4115,15 @@
if (outTransformHint) {
*outTransformHint = mActiveDisplayTransformHint;
}
-
+ args.parentId = LayerHandle::getLayerId(args.parentHandle.promote());
+ args.layerIdToMirror = LayerHandle::getLayerId(args.mirrorLayerHandle.promote());
{
std::scoped_lock<std::mutex> lock(mCreatedLayersLock);
mCreatedLayers.emplace_back(layer, parent, args.addToRoot);
mNewLayers.emplace_back(std::make_unique<frontend::RequestedLayerState>(args));
+ args.mirrorLayerHandle.clear();
+ args.parentHandle.clear();
+ mNewLayerArgs.emplace_back(std::move(args));
}
setTransactionFlags(eTransactionNeeded);
@@ -4119,6 +4147,7 @@
ATRACE_INT("mTransactionFlags", transactionFlags);
if (const bool scheduled = transactionFlags & mask; !scheduled) {
+ mScheduler->resync();
scheduleCommit(frameHint);
} else if (frameHint == FrameHint::kActive) {
// Even if the next frame is already scheduled, we should reset the idle timer
@@ -4261,7 +4290,7 @@
bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactions,
VsyncId vsyncId) {
- Mutex::Autolock _l(mStateLock);
+ Mutex::Autolock lock(mStateLock);
return applyTransactionsLocked(transactions, vsyncId);
}
@@ -4280,10 +4309,6 @@
transaction.listenerCallbacks, transaction.originPid,
transaction.originUid, transaction.id);
}
-
- if (mTransactionTracing) {
- mTransactionTracing->addCommittedTransactions(transactions, vsyncId.value);
- }
return needsTraversal;
}
@@ -4342,9 +4367,8 @@
// We don't want to latch unsignaled if are in early / client composition
// as it leads to jank due to RenderEngine waiting for unsignaled buffer
// or window animations being slow.
- const auto isDefaultVsyncConfig = mScheduler->vsyncModulator().isVsyncConfigDefault();
- if (!isDefaultVsyncConfig) {
- ALOGV("%s: false (LatchUnsignaledConfig::AutoSingleLayer; !isDefaultVsyncConfig)",
+ if (mScheduler->vsyncModulator().isVsyncConfigEarly()) {
+ ALOGV("%s: false (LatchUnsignaledConfig::AutoSingleLayer; isVsyncConfigEarly)",
__func__);
return false;
}
@@ -4423,6 +4447,21 @@
layerName.c_str(), transactionId);
mBufferCountTracker.increment(resolvedState.state.surface->localBinder());
}
+ resolvedState.layerId = LayerHandle::getLayerId(resolvedState.state.surface);
+ if (resolvedState.state.what & layer_state_t::eReparent) {
+ resolvedState.parentId =
+ getLayerIdFromSurfaceControl(resolvedState.state.parentSurfaceControlForChild);
+ }
+ if (resolvedState.state.what & layer_state_t::eRelativeLayerChanged) {
+ resolvedState.relativeParentId =
+ getLayerIdFromSurfaceControl(resolvedState.state.relativeLayerSurfaceControl);
+ }
+ if (resolvedState.state.what & layer_state_t::eInputInfoChanged) {
+ wp<IBinder>& touchableRegionCropHandle =
+ resolvedState.state.windowInfoHandle->editInfo()->touchableRegionCropHandle;
+ resolvedState.touchCropId =
+ LayerHandle::getLayerId(touchableRegionCropHandle.promote());
+ }
}
TransactionState state{frameTimelineInfo,
@@ -4547,7 +4586,7 @@
bool SurfaceFlinger::applyAndCommitDisplayTransactionStates(
std::vector<TransactionState>& transactions) {
- Mutex::Autolock _l(mStateLock);
+ Mutex::Autolock lock(mStateLock);
bool needsTraversal = false;
uint32_t transactionFlags = 0;
for (auto& transaction : transactions) {
@@ -5111,7 +5150,7 @@
sp<Layer> mirrorLayer;
sp<Layer> mirrorFrom;
- LayerCreationArgs mirrorArgs(args);
+ LayerCreationArgs mirrorArgs = LayerCreationArgs::fromOtherArgs(args);
{
Mutex::Autolock _l(mStateLock);
mirrorFrom = LayerHandle::getLayer(mirrorFromHandle);
@@ -5131,11 +5170,6 @@
outResult.layerId = mirrorLayer->sequence;
outResult.layerName = String16(mirrorLayer->getDebugName());
- if (mTransactionTracing) {
- mTransactionTracing->onMirrorLayerAdded(outResult.handle->localBinder(),
- mirrorLayer->sequence, args.name,
- mirrorFrom->sequence);
- }
return addClientLayer(mirrorArgs, outResult.handle, mirrorLayer /* layer */,
nullptr /* parent */, nullptr /* outTransformHint */);
}
@@ -5162,7 +5196,7 @@
}
layerStack = display->getLayerStack();
- LayerCreationArgs mirrorArgs(args);
+ LayerCreationArgs mirrorArgs = LayerCreationArgs::fromOtherArgs(args);
mirrorArgs.flags |= ISurfaceComposerClient::eNoColorFill;
mirrorArgs.addToRoot = true;
mirrorArgs.layerStackToMirror = layerStack;
@@ -5177,11 +5211,6 @@
return result;
}
- if (mTransactionTracing) {
- mTransactionTracing->onLayerAdded(outResult.handle->localBinder(), outResult.layerId,
- args.name, args.flags, -1 /* parentId */);
- }
-
if (mLegacyFrontEndEnabled) {
std::scoped_lock<std::mutex> lock(mMirrorDisplayLock);
mMirrorDisplays.emplace_back(layerStack, outResult.handle, args.client);
@@ -5229,12 +5258,6 @@
args.addToRoot = false;
}
- const int parentId = parent ? parent->getSequence() : -1;
- if (mTransactionTracing) {
- mTransactionTracing->onLayerAdded(outResult.handle->localBinder(), layer->sequence,
- args.name, args.flags, parentId);
- }
-
uint32_t outTransformHint;
result = addClientLayer(args, outResult.handle, layer, parent, &outTransformHint);
if (result != NO_ERROR) {
@@ -5278,15 +5301,12 @@
markLayerPendingRemovalLocked(layer);
mBufferCountTracker.remove(handle);
layer.clear();
- if (mTransactionTracing) {
- mTransactionTracing->onHandleRemoved(handle);
- }
setTransactionFlags(eTransactionFlushNeeded);
}
-void SurfaceFlinger::onInitializeDisplays() {
- const auto display = getDefaultDisplayDeviceLocked();
+void SurfaceFlinger::initializeDisplays() {
+ const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked());
if (!display) return;
const sp<IBinder> token = display->getDisplayToken().promote();
@@ -5294,13 +5314,13 @@
TransactionState state;
state.inputWindowCommands = mInputWindowCommands;
- nsecs_t now = systemTime();
+ const nsecs_t now = systemTime();
state.desiredPresentTime = now;
state.postTime = now;
state.permissions = layer_state_t::ACCESS_SURFACE_FLINGER;
state.originPid = mPid;
state.originUid = static_cast<int>(getuid());
- uint64_t transactionId = (((uint64_t)mPid) << 32) | mUniqueTransactionId++;
+ const uint64_t transactionId = (static_cast<uint64_t>(mPid) << 32) | mUniqueTransactionId++;
state.id = transactionId;
// reset screen orientation and use primary layer stack
@@ -5320,21 +5340,16 @@
std::vector<TransactionState> transactions;
transactions.emplace_back(state);
- // It should be on the main thread, apply it directly.
if (mLegacyFrontEndEnabled) {
- applyTransactionsLocked(transactions, /*vsyncId=*/{0});
+ applyTransactions(transactions, VsyncId{0});
} else {
applyAndCommitDisplayTransactionStates(transactions);
}
- setPowerModeInternal(display, hal::PowerMode::ON);
-}
-
-void SurfaceFlinger::initializeDisplays() {
- // Async since we may be called from the main thread.
- static_cast<void>(mScheduler->schedule(
- [this]() FTL_FAKE_GUARD(mStateLock)
- FTL_FAKE_GUARD(kMainThreadContext) { onInitializeDisplays(); }));
+ {
+ ftl::FakeGuard guard(mStateLock);
+ setPowerModeInternal(display, hal::PowerMode::ON);
+ }
}
void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode) {
@@ -5536,7 +5551,8 @@
LayersTraceProto* layersTrace = traceFileProto.add_entry();
LayersProto layersProto = dumpProtoFromMainThread();
layersTrace->mutable_layers()->Swap(&layersProto);
- dumpDisplayProto(*layersTrace);
+ auto displayProtos = dumpDisplayProto();
+ layersTrace->mutable_displays()->Swap(&displayProtos);
if (asProto) {
result.append(traceFileProto.SerializeAsString());
@@ -5788,9 +5804,10 @@
return layersProto;
}
-void SurfaceFlinger::dumpDisplayProto(LayersTraceProto& layersTraceProto) const {
+google::protobuf::RepeatedPtrField<DisplayProto> SurfaceFlinger::dumpDisplayProto() const {
+ google::protobuf::RepeatedPtrField<DisplayProto> displays;
for (const auto& [_, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) {
- DisplayProto* displayProto = layersTraceProto.add_displays();
+ DisplayProto* displayProto = displays.Add();
displayProto->set_id(display->getId().value);
displayProto->set_name(display->getDisplayName());
displayProto->set_layer_stack(display->getLayerStack().id);
@@ -5803,6 +5820,7 @@
displayProto->mutable_transform());
displayProto->set_is_virtual(display->isVirtual());
}
+ return displays;
}
void SurfaceFlinger::dumpHwc(std::string& result) const {
@@ -6333,9 +6351,10 @@
int64_t startingTime =
(fixedStartingTime) ? fixedStartingTime : systemTime();
mScheduler
- ->schedule([&]() FTL_FAKE_GUARD(mStateLock) {
- mLayerTracing.notify(true /* visibleRegionDirty */,
- startingTime, mLastCommittedVsyncId.value);
+ ->schedule([&]() FTL_FAKE_GUARD(mStateLock) FTL_FAKE_GUARD(
+ kMainThreadContext) {
+ addToLayerTracing(true /* visibleRegionDirty */, startingTime,
+ mLastCommittedVsyncId.value);
})
.wait();
}
@@ -7698,10 +7717,6 @@
if (hintDisplay) {
layer->updateTransformHint(hintDisplay->getTransformHint());
}
-
- if (mTransactionTracing) {
- mTransactionTracing->onLayerAddedToDrawingState(layer->getSequence(), vsyncId.value);
- }
}
void SurfaceFlinger::sample() {
@@ -7721,14 +7736,20 @@
const DisplayDevice& activeDisplay) {
ATRACE_CALL();
+ // For the first display activated during boot, there is no need to force setDesiredActiveMode,
+ // because DM is about to send its policy via setDesiredDisplayModeSpecs.
+ bool forceApplyPolicy = false;
+
if (inactiveDisplayPtr) {
inactiveDisplayPtr->getCompositionDisplay()->setLayerCachingTexturePoolEnabled(false);
+ forceApplyPolicy = true;
}
mActiveDisplayId = activeDisplay.getPhysicalId();
activeDisplay.getCompositionDisplay()->setLayerCachingTexturePoolEnabled(true);
- updateActiveDisplayVsyncLocked(activeDisplay);
+ resetPhaseConfiguration(activeDisplay.getActiveMode().fps);
+
mScheduler->setModeChangePending(false);
mScheduler->setPacesetterDisplay(mActiveDisplayId);
@@ -7739,8 +7760,8 @@
// that case, its preferred mode has not been propagated to HWC (via setDesiredActiveMode). In
// either case, the Scheduler's cachedModeChangedParams must be initialized to the newly active
// mode, and the kernel idle timer of the newly active display must be toggled.
- constexpr bool kForce = true;
- applyRefreshRateSelectorPolicy(mActiveDisplayId, activeDisplay.refreshRateSelector(), kForce);
+ applyRefreshRateSelectorPolicy(mActiveDisplayId, activeDisplay.refreshRateSelector(),
+ forceApplyPolicy);
}
status_t SurfaceFlinger::addWindowInfosListener(
@@ -7836,10 +7857,6 @@
sp<Layer> childMirror;
createEffectLayer(mirrorArgs, &unused, &childMirror);
childMirror->setClonedChild(layer->createClone());
- if (mTransactionTracing) {
- mTransactionTracing->onLayerAddedToDrawingState(childMirror->getSequence(),
- vsyncId.value);
- }
childMirror->reparent(mirrorDisplay.rootHandle);
}
}
@@ -8024,8 +8041,8 @@
};
}
-SurfaceFlinger::LifecycleUpdate SurfaceFlinger::flushLifecycleUpdates() {
- LifecycleUpdate update;
+frontend::Update SurfaceFlinger::flushLifecycleUpdates() {
+ frontend::Update update;
ATRACE_NAME("TransactionHandler:flushTransactions");
// Locking:
// 1. to prevent onHandleDestroyed from being called while the state lock is held,
@@ -8042,12 +8059,28 @@
mCreatedLayers.clear();
update.newLayers = std::move(mNewLayers);
mNewLayers.clear();
+ update.layerCreationArgs = std::move(mNewLayerArgs);
+ mNewLayerArgs.clear();
update.destroyedHandles = std::move(mDestroyedHandles);
mDestroyedHandles.clear();
}
return update;
}
+void SurfaceFlinger::addToLayerTracing(bool visibleRegionDirty, int64_t time, int64_t vsyncId) {
+ const uint32_t tracingFlags = mLayerTracing.getFlags();
+ LayersProto layers(dumpDrawingStateProto(tracingFlags));
+ if (tracingFlags & LayerTracing::TRACE_EXTRA) {
+ dumpOffscreenLayersProto(layers);
+ }
+ std::string hwcDump;
+ if (tracingFlags & LayerTracing::TRACE_HWC) {
+ dumpHwc(hwcDump);
+ }
+ auto displays = dumpDisplayProto();
+ mLayerTracing.notify(visibleRegionDirty, time, vsyncId, &layers, std::move(hwcDump), &displays);
+}
+
// gui::ISurfaceComposer
binder::Status SurfaceComposerAIDL::bootFinished() {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 338531f..42d5db7 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -455,26 +455,6 @@
FINISHED,
};
- struct LayerCreatedState {
- LayerCreatedState(const wp<Layer>& layer, const wp<Layer>& parent, bool addToRoot)
- : layer(layer), initialParent(parent), addToRoot(addToRoot) {}
- wp<Layer> layer;
- // Indicates the initial parent of the created layer, only used for creating layer in
- // SurfaceFlinger. If nullptr, it may add the created layer into the current root layers.
- wp<Layer> initialParent;
- // Indicates whether the layer getting created should be added at root if there's no parent
- // and has permission ACCESS_SURFACE_FLINGER. If set to false and no parent, the layer will
- // be added offscreen.
- bool addToRoot;
- };
-
- struct LifecycleUpdate {
- std::vector<TransactionState> transactions;
- std::vector<LayerCreatedState> layerCreatedStates;
- std::vector<std::unique_ptr<frontend::RequestedLayerState>> newLayers;
- std::vector<uint32_t> destroyedHandles;
- };
-
template <typename F, std::enable_if_t<!std::is_member_function_pointer_v<F>>* = nullptr>
static Dumper dumper(F&& dump) {
using namespace std::placeholders;
@@ -721,13 +701,13 @@
int64_t vsyncId);
void moveSnapshotsFromCompositionArgs(compositionengine::CompositionRefreshArgs& refreshArgs,
std::vector<std::pair<Layer*, LayerFE*>>& layers);
- bool updateLayerSnapshotsLegacy(VsyncId vsyncId, LifecycleUpdate& update,
+ bool updateLayerSnapshotsLegacy(VsyncId vsyncId, frontend::Update& update,
bool transactionsFlushed, bool& out)
REQUIRES(kMainThreadContext);
- bool updateLayerSnapshots(VsyncId vsyncId, LifecycleUpdate& update, bool transactionsFlushed,
+ bool updateLayerSnapshots(VsyncId vsyncId, frontend::Update& update, bool transactionsFlushed,
bool& out) REQUIRES(kMainThreadContext);
void updateLayerHistory(const frontend::LayerSnapshot& snapshot);
- LifecycleUpdate flushLifecycleUpdates() REQUIRES(kMainThreadContext);
+ frontend::Update flushLifecycleUpdates() REQUIRES(kMainThreadContext);
void updateInputFlinger();
void persistDisplayBrightness(bool needsComposite) REQUIRES(kMainThreadContext);
@@ -737,6 +717,8 @@
void updateCursorAsync();
void initScheduler(const sp<const DisplayDevice>&) REQUIRES(kMainThreadContext, mStateLock);
+
+ void resetPhaseConfiguration(Fps) REQUIRES(mStateLock, kMainThreadContext);
void updatePhaseConfiguration(Fps) REQUIRES(mStateLock);
/*
@@ -818,7 +800,7 @@
void markLayerPendingRemovalLocked(const sp<Layer>& layer);
// add a layer to SurfaceFlinger
- status_t addClientLayer(const LayerCreationArgs& args, const sp<IBinder>& handle,
+ status_t addClientLayer(LayerCreationArgs& args, const sp<IBinder>& handle,
const sp<Layer>& layer, const wp<Layer>& parentLayer,
uint32_t* outTransformHint);
@@ -855,8 +837,7 @@
*/
// Called during boot, and restart after system_server death.
- void initializeDisplays();
- void onInitializeDisplays() REQUIRES(mStateLock, kMainThreadContext);
+ void initializeDisplays() REQUIRES(kMainThreadContext);
sp<const DisplayDevice> getDisplayDeviceLocked(const wp<IBinder>& displayToken) const
REQUIRES(mStateLock) {
@@ -1085,7 +1066,9 @@
LayersProto dumpDrawingStateProto(uint32_t traceFlags) const;
void dumpOffscreenLayersProto(LayersProto& layersProto,
uint32_t traceFlags = LayerTracing::TRACE_ALL) const;
- void dumpDisplayProto(LayersTraceProto& layersTraceProto) const;
+ google::protobuf::RepeatedPtrField<DisplayProto> dumpDisplayProto() const;
+ void addToLayerTracing(bool visibleRegionDirty, int64_t time, int64_t vsyncId)
+ REQUIRES(kMainThreadContext);
// Dumps state from HW Composer
void dumpHwc(std::string& result) const;
@@ -1121,9 +1104,6 @@
std::chrono::nanoseconds presentLatency);
int getMaxAcquiredBufferCountForRefreshRate(Fps refreshRate) const;
- void updateActiveDisplayVsyncLocked(const DisplayDevice& activeDisplay)
- REQUIRES(mStateLock, kMainThreadContext);
-
bool isHdrLayer(const frontend::LayerSnapshot& snapshot) const;
ui::Rotation getPhysicalDisplayOrientation(DisplayId, bool isPrimary) const
@@ -1242,7 +1222,7 @@
bool mLayerCachingEnabled = false;
bool mBackpressureGpuComposition = false;
- LayerTracing mLayerTracing{*this};
+ LayerTracing mLayerTracing;
bool mLayerTracingEnabled = false;
std::optional<TransactionTracing> mTransactionTracing;
@@ -1424,6 +1404,7 @@
std::vector<uint32_t> mDestroyedHandles;
std::vector<std::unique_ptr<frontend::RequestedLayerState>> mNewLayers;
+ std::vector<LayerCreationArgs> mNewLayerArgs;
// These classes do not store any client state but help with managing transaction callbacks
// and stats.
std::unordered_map<uint32_t, sp<Layer>> mLegacyLayers;
diff --git a/services/surfaceflinger/Tracing/LayerTracing.cpp b/services/surfaceflinger/Tracing/LayerTracing.cpp
index 566d553..2918f7c 100644
--- a/services/surfaceflinger/Tracing/LayerTracing.cpp
+++ b/services/surfaceflinger/Tracing/LayerTracing.cpp
@@ -29,9 +29,8 @@
namespace android {
-LayerTracing::LayerTracing(SurfaceFlinger& flinger) : mFlinger(flinger) {
- mBuffer = std::make_unique<RingBuffer<LayersTraceFileProto, LayersTraceProto>>();
-}
+LayerTracing::LayerTracing()
+ : mBuffer(std::make_unique<RingBuffer<LayersTraceFileProto, LayersTraceProto>>()) {}
LayerTracing::~LayerTracing() = default;
@@ -84,8 +83,11 @@
bool LayerTracing::flagIsSet(uint32_t flags) const {
return (mFlags & flags) == flags;
}
+uint32_t LayerTracing::getFlags() const {
+ return mFlags;
+}
-LayersTraceFileProto LayerTracing::createTraceFileProto() const {
+LayersTraceFileProto LayerTracing::createTraceFileProto() {
LayersTraceFileProto fileProto;
fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 |
LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L);
@@ -101,7 +103,9 @@
mBuffer->dump(result);
}
-void LayerTracing::notify(bool visibleRegionDirty, int64_t time, int64_t vsyncId) {
+void LayerTracing::notify(bool visibleRegionDirty, int64_t time, int64_t vsyncId,
+ LayersProto* layers, std::string hwcDump,
+ google::protobuf::RepeatedPtrField<DisplayProto>* displays) {
std::scoped_lock lock(mTraceLock);
if (!mEnabled) {
return;
@@ -116,22 +120,15 @@
entry.set_elapsed_realtime_nanos(time);
const char* where = visibleRegionDirty ? "visibleRegionsDirty" : "bufferLatched";
entry.set_where(where);
- LayersProto layers(mFlinger.dumpDrawingStateProto(mFlags));
-
- if (flagIsSet(LayerTracing::TRACE_EXTRA)) {
- mFlinger.dumpOffscreenLayersProto(layers);
- }
- entry.mutable_layers()->Swap(&layers);
+ entry.mutable_layers()->Swap(layers);
if (flagIsSet(LayerTracing::TRACE_HWC)) {
- std::string hwcDump;
- mFlinger.dumpHwc(hwcDump);
entry.set_hwc_blob(hwcDump);
}
if (!flagIsSet(LayerTracing::TRACE_COMPOSITION)) {
entry.set_excludes_composition_state(true);
}
- mFlinger.dumpDisplayProto(entry);
+ entry.mutable_displays()->Swap(displays);
entry.set_vsync_id(vsyncId);
mBuffer->emplace(std::move(entry));
}
diff --git a/services/surfaceflinger/Tracing/LayerTracing.h b/services/surfaceflinger/Tracing/LayerTracing.h
index b32001c..11bb9f4 100644
--- a/services/surfaceflinger/Tracing/LayerTracing.h
+++ b/services/surfaceflinger/Tracing/LayerTracing.h
@@ -40,14 +40,15 @@
*/
class LayerTracing {
public:
- LayerTracing(SurfaceFlinger& flinger);
+ LayerTracing();
~LayerTracing();
bool enable();
bool disable(std::string filename = FILE_NAME);
bool isEnabled() const;
status_t writeToFile();
- LayersTraceFileProto createTraceFileProto() const;
- void notify(bool visibleRegionDirty, int64_t time, int64_t vsyncId);
+ static LayersTraceFileProto createTraceFileProto();
+ void notify(bool visibleRegionDirty, int64_t time, int64_t vsyncId, LayersProto* layers,
+ std::string hwcDump, google::protobuf::RepeatedPtrField<DisplayProto>* displays);
enum : uint32_t {
TRACE_INPUT = 1 << 1,
@@ -60,13 +61,12 @@
};
void setTraceFlags(uint32_t flags);
bool flagIsSet(uint32_t flags) const;
+ uint32_t getFlags() const;
void setBufferSize(size_t bufferSizeInBytes);
void dump(std::string&) const;
private:
static constexpr auto FILE_NAME = "/data/misc/wmtrace/layers_trace.winscope";
-
- SurfaceFlinger& mFlinger;
uint32_t mFlags = TRACE_INPUT;
mutable std::mutex mTraceLock;
bool mEnabled GUARDED_BY(mTraceLock) = false;
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
index ba08cee..8fd6538 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
@@ -15,15 +15,43 @@
*/
#include <gui/SurfaceComposerClient.h>
-#include <renderengine/mock/FakeExternalTexture.h>
#include <ui/Fence.h>
#include <ui/Rect.h>
+#include "FrontEnd/LayerCreationArgs.h"
#include "LayerProtoHelper.h"
#include "TransactionProtoParser.h"
+#include "TransactionState.h"
+#include "gui/LayerState.h"
namespace android::surfaceflinger {
+class FakeExternalTexture : public renderengine::ExternalTexture {
+ const sp<GraphicBuffer> mEmptyBuffer =
+ sp<GraphicBuffer>::make(1u, 1u, PIXEL_FORMAT_RGBA_8888,
+ GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN);
+ uint32_t mWidth;
+ uint32_t mHeight;
+ uint64_t mId;
+ PixelFormat mPixelFormat;
+ uint64_t mUsage;
+
+public:
+ FakeExternalTexture(uint32_t width, uint32_t height, uint64_t id, PixelFormat pixelFormat,
+ uint64_t usage)
+ : mWidth(width), mHeight(height), mId(id), mPixelFormat(pixelFormat), mUsage(usage) {}
+ const sp<GraphicBuffer>& getBuffer() const { return mEmptyBuffer; }
+ bool hasSameBuffer(const renderengine::ExternalTexture& other) const override {
+ return getId() == other.getId();
+ }
+ uint32_t getWidth() const override { return mWidth; }
+ uint32_t getHeight() const override { return mHeight; }
+ uint64_t getId() const override { return mId; }
+ PixelFormat getPixelFormat() const override { return mPixelFormat; }
+ uint64_t getUsage() const override { return mUsage; }
+ ~FakeExternalTexture() = default;
+};
+
proto::TransactionState TransactionProtoParser::toProto(const TransactionState& t) {
proto::TransactionState proto;
proto.set_pid(t.originPid);
@@ -35,7 +63,7 @@
proto.mutable_layer_changes()->Reserve(static_cast<int32_t>(t.states.size()));
for (auto& layerState : t.states) {
- proto.mutable_layer_changes()->Add(std::move(toProto(layerState.state)));
+ proto.mutable_layer_changes()->Add(std::move(toProto(layerState)));
}
proto.mutable_display_changes()->Reserve(static_cast<int32_t>(t.displays.size()));
@@ -46,40 +74,22 @@
}
proto::TransactionState TransactionProtoParser::toProto(
- const std::map<int32_t /* layerId */, TracingLayerState>& states) {
+ const std::map<uint32_t /* layerId */, TracingLayerState>& states) {
proto::TransactionState proto;
proto.mutable_layer_changes()->Reserve(static_cast<int32_t>(states.size()));
for (auto& [layerId, state] : states) {
proto::LayerState layerProto = toProto(state);
- if (layerProto.has_buffer_data()) {
- proto::LayerState_BufferData* bufferProto = layerProto.mutable_buffer_data();
- bufferProto->set_buffer_id(state.bufferId);
- bufferProto->set_width(state.bufferWidth);
- bufferProto->set_height(state.bufferHeight);
- bufferProto->set_pixel_format(
- static_cast<proto::LayerState_BufferData_PixelFormat>(state.pixelFormat));
- bufferProto->set_usage(state.bufferUsage);
- }
layerProto.set_has_sideband_stream(state.hasSidebandStream);
- layerProto.set_layer_id(state.layerId);
- layerProto.set_parent_id(state.parentId);
- layerProto.set_relative_parent_id(state.relativeParentId);
- if (layerProto.has_window_info_handle()) {
- layerProto.mutable_window_info_handle()->set_crop_layer_id(state.inputCropId);
- }
proto.mutable_layer_changes()->Add(std::move(layerProto));
}
return proto;
}
-proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer) {
+proto::LayerState TransactionProtoParser::toProto(
+ const ResolvedComposerState& resolvedComposerState) {
proto::LayerState proto;
- if (layer.surface) {
- proto.set_layer_id(mMapper->getLayerId(layer.surface));
- } else {
- proto.set_layer_id(layer.layerId);
- }
-
+ auto& layer = resolvedComposerState.state;
+ proto.set_layer_id(resolvedComposerState.layerId);
proto.set_what(layer.what);
if (layer.what & layer_state_t::ePositionChanged) {
@@ -135,27 +145,13 @@
}
if (layer.what & layer_state_t::eBufferChanged) {
proto::LayerState_BufferData* bufferProto = proto.mutable_buffer_data();
- if (layer.bufferData->hasBuffer()) {
- bufferProto->set_buffer_id(layer.bufferData->getId());
- bufferProto->set_width(layer.bufferData->getWidth());
- bufferProto->set_height(layer.bufferData->getHeight());
+ if (resolvedComposerState.externalTexture) {
+ bufferProto->set_buffer_id(resolvedComposerState.externalTexture->getId());
+ bufferProto->set_width(resolvedComposerState.externalTexture->getWidth());
+ bufferProto->set_height(resolvedComposerState.externalTexture->getHeight());
bufferProto->set_pixel_format(static_cast<proto::LayerState_BufferData_PixelFormat>(
- layer.bufferData->getPixelFormat()));
- bufferProto->set_usage(layer.bufferData->getUsage());
- } else {
- uint64_t bufferId;
- uint32_t width;
- uint32_t height;
- int32_t pixelFormat;
- uint64_t usage;
- mMapper->getGraphicBufferPropertiesFromCache(layer.bufferData->cachedBuffer, &bufferId,
- &width, &height, &pixelFormat, &usage);
- bufferProto->set_buffer_id(bufferId);
- bufferProto->set_width(width);
- bufferProto->set_height(height);
- bufferProto->set_pixel_format(
- static_cast<proto::LayerState_BufferData_PixelFormat>(pixelFormat));
- bufferProto->set_usage(usage);
+ resolvedComposerState.externalTexture->getPixelFormat()));
+ bufferProto->set_usage(resolvedComposerState.externalTexture->getUsage());
}
bufferProto->set_frame_number(layer.bufferData->frameNumber);
bufferProto->set_flags(layer.bufferData->flags.get());
@@ -179,16 +175,10 @@
}
if (layer.what & layer_state_t::eReparent) {
- int64_t layerId = layer.parentSurfaceControlForChild
- ? mMapper->getLayerId(layer.parentSurfaceControlForChild->getHandle())
- : -1;
- proto.set_parent_id(layerId);
+ proto.set_parent_id(resolvedComposerState.parentId);
}
if (layer.what & layer_state_t::eRelativeLayerChanged) {
- int64_t layerId = layer.relativeLayerSurfaceControl
- ? mMapper->getLayerId(layer.relativeLayerSurfaceControl->getHandle())
- : -1;
- proto.set_relative_parent_id(layerId);
+ proto.set_relative_parent_id(resolvedComposerState.relativeParentId);
proto.set_z(layer.z);
}
@@ -207,7 +197,7 @@
windowInfoProto->set_has_wallpaper(inputInfo->inputConfig.test(
gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER));
windowInfoProto->set_global_scale_factor(inputInfo->globalScaleFactor);
- proto::LayerState_Transform* transformProto = windowInfoProto->mutable_transform();
+ proto::Transform* transformProto = windowInfoProto->mutable_transform();
transformProto->set_dsdx(inputInfo->transform.dsdx());
transformProto->set_dtdx(inputInfo->transform.dtdx());
transformProto->set_dtdy(inputInfo->transform.dtdy());
@@ -216,8 +206,7 @@
transformProto->set_ty(inputInfo->transform.ty());
windowInfoProto->set_replace_touchable_region_with_crop(
inputInfo->replaceTouchableRegionWithCrop);
- windowInfoProto->set_crop_layer_id(
- mMapper->getLayerId(inputInfo->touchableRegionCropHandle.promote()));
+ windowInfoProto->set_crop_layer_id(resolvedComposerState.touchCropId);
}
}
if (layer.what & layer_state_t::eBackgroundColorChanged) {
@@ -289,13 +278,15 @@
return proto;
}
-proto::LayerCreationArgs TransactionProtoParser::toProto(const TracingLayerCreationArgs& args) {
+proto::LayerCreationArgs TransactionProtoParser::toProto(const LayerCreationArgs& args) {
proto::LayerCreationArgs proto;
- proto.set_layer_id(args.layerId);
+ proto.set_layer_id(args.sequence);
proto.set_name(args.name);
proto.set_flags(args.flags);
proto.set_parent_id(args.parentId);
- proto.set_mirror_from_id(args.mirrorFromId);
+ proto.set_mirror_from_id(args.layerIdToMirror);
+ proto.set_add_to_root(args.addToRoot);
+ proto.set_layer_stack_to_mirror(args.layerStackToMirror.id);
return proto;
}
@@ -313,15 +304,7 @@
for (int i = 0; i < layerCount; i++) {
ResolvedComposerState s;
s.state.what = 0;
- fromProto(proto.layer_changes(i), s.state);
- if (s.state.bufferData) {
- s.externalTexture = std::make_shared<
- renderengine::mock::FakeExternalTexture>(s.state.bufferData->getWidth(),
- s.state.bufferData->getHeight(),
- s.state.bufferData->getId(),
- s.state.bufferData->getPixelFormat(),
- s.state.bufferData->getUsage());
- }
+ fromProto(proto.layer_changes(i), s);
t.states.emplace_back(s);
}
@@ -334,46 +317,47 @@
}
void TransactionProtoParser::fromProto(const proto::LayerCreationArgs& proto,
- TracingLayerCreationArgs& outArgs) {
- outArgs.layerId = proto.layer_id();
+ LayerCreationArgs& outArgs) {
+ outArgs.sequence = proto.layer_id();
+
outArgs.name = proto.name();
outArgs.flags = proto.flags();
outArgs.parentId = proto.parent_id();
- outArgs.mirrorFromId = proto.mirror_from_id();
+ outArgs.layerIdToMirror = proto.mirror_from_id();
+ outArgs.addToRoot = proto.add_to_root();
+ outArgs.layerStackToMirror.id = proto.layer_stack_to_mirror();
}
void TransactionProtoParser::mergeFromProto(const proto::LayerState& proto,
TracingLayerState& outState) {
- layer_state_t state;
- fromProto(proto, state);
- outState.merge(state);
+ ResolvedComposerState resolvedComposerState;
+ fromProto(proto, resolvedComposerState);
+ layer_state_t& state = resolvedComposerState.state;
+ outState.state.merge(state);
+ outState.layerId = resolvedComposerState.layerId;
if (state.what & layer_state_t::eReparent) {
- outState.parentId = static_cast<int32_t>(proto.parent_id());
+ outState.parentId = resolvedComposerState.parentId;
}
if (state.what & layer_state_t::eRelativeLayerChanged) {
- outState.relativeParentId = static_cast<int32_t>(proto.relative_parent_id());
+ outState.relativeParentId = resolvedComposerState.relativeParentId;
}
if (state.what & layer_state_t::eInputInfoChanged) {
- outState.inputCropId = static_cast<int32_t>(proto.window_info_handle().crop_layer_id());
+ outState.touchCropId = resolvedComposerState.touchCropId;
}
if (state.what & layer_state_t::eBufferChanged) {
- const proto::LayerState_BufferData& bufferProto = proto.buffer_data();
- outState.bufferId = bufferProto.buffer_id();
- outState.bufferWidth = bufferProto.width();
- outState.bufferHeight = bufferProto.height();
- outState.pixelFormat = bufferProto.pixel_format();
- outState.bufferUsage = bufferProto.usage();
+ outState.externalTexture = resolvedComposerState.externalTexture;
}
if (state.what & layer_state_t::eSidebandStreamChanged) {
outState.hasSidebandStream = proto.has_sideband_stream();
}
}
-void TransactionProtoParser::fromProto(const proto::LayerState& proto, layer_state_t& layer) {
- layer.layerId = (int32_t)proto.layer_id();
+void TransactionProtoParser::fromProto(const proto::LayerState& proto,
+ ResolvedComposerState& resolvedComposerState) {
+ auto& layer = resolvedComposerState.state;
+ resolvedComposerState.layerId = proto.layer_id();
layer.what |= proto.what();
- layer.surface = mMapper->getLayerHandle(layer.layerId);
if (proto.what() & layer_state_t::ePositionChanged) {
layer.x = proto.x();
@@ -428,9 +412,15 @@
if (proto.what() & layer_state_t::eBufferChanged) {
const proto::LayerState_BufferData& bufferProto = proto.buffer_data();
layer.bufferData =
- std::move(mMapper->getGraphicData(bufferProto.buffer_id(), bufferProto.width(),
- bufferProto.height(), bufferProto.pixel_format(),
- bufferProto.usage()));
+ std::make_shared<fake::BufferData>(bufferProto.buffer_id(), bufferProto.width(),
+ bufferProto.height(), bufferProto.pixel_format(),
+ bufferProto.usage());
+ resolvedComposerState.externalTexture =
+ std::make_shared<FakeExternalTexture>(layer.bufferData->getWidth(),
+ layer.bufferData->getHeight(),
+ layer.bufferData->getId(),
+ layer.bufferData->getPixelFormat(),
+ layer.bufferData->getUsage());
layer.bufferData->frameNumber = bufferProto.frame_number();
layer.bufferData->flags = ftl::Flags<BufferData::BufferDataChange>(bufferProto.flags());
layer.bufferData->cachedBuffer.id = bufferProto.cached_buffer_id();
@@ -454,26 +444,10 @@
}
if (proto.what() & layer_state_t::eReparent) {
- int64_t layerId = proto.parent_id();
- if (layerId == -1) {
- layer.parentSurfaceControlForChild = nullptr;
- } else {
- layer.parentSurfaceControlForChild =
- sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(),
- mMapper->getLayerHandle(static_cast<int32_t>(layerId)),
- static_cast<int32_t>(layerId), "");
- }
+ resolvedComposerState.parentId = proto.parent_id();
}
if (proto.what() & layer_state_t::eRelativeLayerChanged) {
- int64_t layerId = proto.relative_parent_id();
- if (layerId == -1) {
- layer.relativeLayerSurfaceControl = nullptr;
- } else {
- layer.relativeLayerSurfaceControl =
- sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(),
- mMapper->getLayerHandle(static_cast<int32_t>(layerId)),
- static_cast<int32_t>(layerId), "");
- }
+ resolvedComposerState.relativeParentId = proto.relative_parent_id();
layer.z = proto.z();
}
@@ -493,19 +467,13 @@
inputInfo.setInputConfig(gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER,
windowInfoProto.has_wallpaper());
inputInfo.globalScaleFactor = windowInfoProto.global_scale_factor();
- const proto::LayerState_Transform& transformProto = windowInfoProto.transform();
+ const proto::Transform& transformProto = windowInfoProto.transform();
inputInfo.transform.set(transformProto.dsdx(), transformProto.dtdx(), transformProto.dtdy(),
transformProto.dsdy());
inputInfo.transform.set(transformProto.tx(), transformProto.ty());
inputInfo.replaceTouchableRegionWithCrop =
windowInfoProto.replace_touchable_region_with_crop();
- int64_t layerId = windowInfoProto.crop_layer_id();
- if (layerId != -1) {
- inputInfo.touchableRegionCropHandle =
- mMapper->getLayerHandle(static_cast<int32_t>(layerId));
- } else {
- inputInfo.touchableRegionCropHandle = wp<IBinder>();
- }
+ resolvedComposerState.touchCropId = windowInfoProto.crop_layer_id();
layer.windowInfoHandle = sp<gui::WindowInfoHandle>::make(inputInfo);
}
@@ -577,4 +545,62 @@
return display;
}
+void asProto(proto::Transform* proto, const ui::Transform& transform) {
+ proto->set_dsdx(transform.dsdx());
+ proto->set_dtdx(transform.dtdx());
+ proto->set_dtdy(transform.dtdy());
+ proto->set_dsdy(transform.dsdy());
+ proto->set_tx(transform.tx());
+ proto->set_ty(transform.ty());
+}
+
+proto::DisplayInfo TransactionProtoParser::toProto(const frontend::DisplayInfo& displayInfo,
+ uint32_t layerStack) {
+ proto::DisplayInfo proto;
+ proto.set_layer_stack(layerStack);
+ proto.set_display_id(displayInfo.info.displayId);
+ proto.set_logical_width(displayInfo.info.logicalWidth);
+ proto.set_logical_height(displayInfo.info.logicalHeight);
+ asProto(proto.mutable_transform_inverse(), displayInfo.info.transform);
+ asProto(proto.mutable_transform(), displayInfo.transform);
+ proto.set_receives_input(displayInfo.receivesInput);
+ proto.set_is_secure(displayInfo.isSecure);
+ proto.set_is_primary(displayInfo.isPrimary);
+ proto.set_is_virtual(displayInfo.isVirtual);
+ proto.set_rotation_flags((int)displayInfo.rotationFlags);
+ proto.set_transform_hint((int)displayInfo.transformHint);
+ return proto;
+}
+
+void fromProto2(ui::Transform& outTransform, const proto::Transform& proto) {
+ outTransform.set(proto.dsdx(), proto.dtdx(), proto.dtdy(), proto.dsdy());
+ outTransform.set(proto.tx(), proto.ty());
+}
+
+frontend::DisplayInfo TransactionProtoParser::fromProto(const proto::DisplayInfo& proto) {
+ frontend::DisplayInfo displayInfo;
+ displayInfo.info.displayId = proto.display_id();
+ displayInfo.info.logicalWidth = proto.logical_width();
+ displayInfo.info.logicalHeight = proto.logical_height();
+ fromProto2(displayInfo.info.transform, proto.transform_inverse());
+ fromProto2(displayInfo.transform, proto.transform());
+ displayInfo.receivesInput = proto.receives_input();
+ displayInfo.isSecure = proto.is_secure();
+ displayInfo.isPrimary = proto.is_primary();
+ displayInfo.isPrimary = proto.is_virtual();
+ displayInfo.rotationFlags = (ui::Transform::RotationFlags)proto.rotation_flags();
+ displayInfo.transformHint = (ui::Transform::RotationFlags)proto.transform_hint();
+ return displayInfo;
+}
+
+void TransactionProtoParser::fromProto(
+ const google::protobuf::RepeatedPtrField<proto::DisplayInfo>& proto,
+ display::DisplayMap<ui::LayerStack, frontend::DisplayInfo> outDisplayInfos) {
+ outDisplayInfos.clear();
+ for (const proto::DisplayInfo& displayInfo : proto) {
+ outDisplayInfos.emplace_or_replace(ui::LayerStack::fromValue(displayInfo.layer_stack()),
+ fromProto(displayInfo));
+ }
+}
+
} // namespace android::surfaceflinger
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.h b/services/surfaceflinger/Tracing/TransactionProtoParser.h
index 2232bb9..50944fc 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.h
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.h
@@ -18,30 +18,17 @@
#include <gui/fake/BufferData.h>
#include <layerproto/TransactionProto.h>
#include <utils/RefBase.h>
+#include "Display/DisplayMap.h"
+#include "FrontEnd/DisplayInfo.h"
+#include "FrontEnd/LayerCreationArgs.h"
#include "TransactionState.h"
namespace android::surfaceflinger {
-struct TracingLayerCreationArgs {
- int32_t layerId;
- std::string name;
- uint32_t flags = 0;
- int32_t parentId = -1;
- int32_t mirrorFromId = -1;
-};
-
-struct TracingLayerState : layer_state_t {
- uint64_t bufferId;
- uint32_t bufferHeight;
- uint32_t bufferWidth;
- int32_t pixelFormat;
- uint64_t bufferUsage;
+struct TracingLayerState : ResolvedComposerState {
bool hasSidebandStream;
- int32_t parentId;
- int32_t relativeParentId;
- int32_t inputCropId;
- TracingLayerCreationArgs args;
+ LayerCreationArgs args;
};
class TransactionProtoParser {
@@ -51,40 +38,30 @@
class FlingerDataMapper {
public:
virtual ~FlingerDataMapper() = default;
- virtual sp<IBinder> getLayerHandle(int32_t /* layerId */) const { return nullptr; }
- virtual int64_t getLayerId(const sp<IBinder>& /* layerHandle */) const { return -1; }
- virtual int64_t getLayerId(BBinder* /* layerHandle */) const { return -1; }
virtual sp<IBinder> getDisplayHandle(int32_t /* displayId */) const { return nullptr; }
virtual int32_t getDisplayId(const sp<IBinder>& /* displayHandle */) const { return -1; }
- virtual std::shared_ptr<BufferData> getGraphicData(uint64_t bufferId, uint32_t width,
- uint32_t height, int32_t pixelFormat,
- uint64_t usage) const {
- return std::make_shared<fake::BufferData>(bufferId, width, height, pixelFormat, usage);
- }
- virtual void getGraphicBufferPropertiesFromCache(client_cache_t /* cachedBuffer */,
- uint64_t* /* outBufferId */,
- uint32_t* /* outWidth */,
- uint32_t* /* outHeight */,
- int32_t* /* outPixelFormat */,
- uint64_t* /* outUsage */) const {}
};
TransactionProtoParser(std::unique_ptr<FlingerDataMapper> provider)
: mMapper(std::move(provider)) {}
proto::TransactionState toProto(const TransactionState&);
- proto::TransactionState toProto(const std::map<int32_t /* layerId */, TracingLayerState>&);
- proto::LayerCreationArgs toProto(const TracingLayerCreationArgs& args);
+ proto::TransactionState toProto(const std::map<uint32_t /* layerId */, TracingLayerState>&);
+ proto::LayerCreationArgs toProto(const LayerCreationArgs& args);
+ proto::LayerState toProto(const ResolvedComposerState&);
+ proto::DisplayInfo toProto(const frontend::DisplayInfo&, uint32_t layerStack);
TransactionState fromProto(const proto::TransactionState&);
void mergeFromProto(const proto::LayerState&, TracingLayerState& outState);
- void fromProto(const proto::LayerCreationArgs&, TracingLayerCreationArgs& outArgs);
+ void fromProto(const proto::LayerCreationArgs&, LayerCreationArgs& outArgs);
std::unique_ptr<FlingerDataMapper> mMapper;
+ frontend::DisplayInfo fromProto(const proto::DisplayInfo&);
+ void fromProto(const google::protobuf::RepeatedPtrField<proto::DisplayInfo>&,
+ display::DisplayMap<ui::LayerStack, frontend::DisplayInfo> outDisplayInfos);
private:
- proto::LayerState toProto(const layer_state_t&);
proto::DisplayState toProto(const DisplayState&);
- void fromProto(const proto::LayerState&, layer_state_t& out);
+ void fromProto(const proto::LayerState&, ResolvedComposerState& out);
DisplayState fromProto(const proto::DisplayState&);
};
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.cpp b/services/surfaceflinger/Tracing/TransactionTracing.cpp
index cb5320b..26ed878 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.cpp
+++ b/services/surfaceflinger/Tracing/TransactionTracing.cpp
@@ -23,75 +23,14 @@
#include <utils/SystemClock.h>
#include <utils/Trace.h>
-#include "ClientCache.h"
+#include "Client.h"
+#include "FrontEnd/LayerCreationArgs.h"
#include "TransactionTracing.h"
-#include "renderengine/ExternalTexture.h"
namespace android {
-// Keeps the binder address as the layer id so we can avoid holding the tracing lock in the
-// binder thread.
-class FlatDataMapper : public TransactionProtoParser::FlingerDataMapper {
-public:
- virtual int64_t getLayerId(const sp<IBinder>& layerHandle) const {
- if (layerHandle == nullptr) {
- return -1;
- }
-
- return reinterpret_cast<int64_t>(layerHandle->localBinder());
- }
-
- void getGraphicBufferPropertiesFromCache(client_cache_t cachedBuffer, uint64_t* outBufferId,
- uint32_t* outWidth, uint32_t* outHeight,
- int32_t* outPixelFormat,
- uint64_t* outUsage) const override {
- std::shared_ptr<renderengine::ExternalTexture> buffer =
- ClientCache::getInstance().get(cachedBuffer);
- if (!buffer || !buffer->getBuffer()) {
- *outBufferId = 0;
- *outWidth = 0;
- *outHeight = 0;
- *outPixelFormat = 0;
- *outUsage = 0;
- return;
- }
-
- *outBufferId = buffer->getId();
- *outWidth = buffer->getWidth();
- *outHeight = buffer->getHeight();
- *outPixelFormat = buffer->getPixelFormat();
- *outUsage = buffer->getUsage();
- return;
- }
-};
-
-class FlingerDataMapper : public FlatDataMapper {
- std::unordered_map<BBinder* /* layerHandle */, int32_t /* layerId */>& mLayerHandles;
-
-public:
- FlingerDataMapper(std::unordered_map<BBinder* /* handle */, int32_t /* id */>& layerHandles)
- : mLayerHandles(layerHandles) {}
-
- int64_t getLayerId(const sp<IBinder>& layerHandle) const override {
- if (layerHandle == nullptr) {
- return -1;
- }
- return getLayerId(layerHandle->localBinder());
- }
-
- int64_t getLayerId(BBinder* localBinder) const {
- auto it = mLayerHandles.find(localBinder);
- if (it == mLayerHandles.end()) {
- ALOGW("Could not find layer handle %p", localBinder);
- return -1;
- }
- return it->second;
- }
-};
-
TransactionTracing::TransactionTracing()
- : mProtoParser(std::make_unique<FlingerDataMapper>(mLayerHandles)),
- mLockfreeProtoParser(std::make_unique<FlatDataMapper>()) {
+ : mProtoParser(std::make_unique<TransactionProtoParser::FlingerDataMapper>()) {
std::scoped_lock lock(mTraceLock);
mBuffer.setSize(mBufferSizeInBytes);
@@ -137,84 +76,77 @@
auto timeOffsetNs = static_cast<std::uint64_t>(systemTime(SYSTEM_TIME_REALTIME) -
systemTime(SYSTEM_TIME_MONOTONIC));
proto.set_real_to_elapsed_time_offset_nanos(timeOffsetNs);
+ proto.set_version(TRACING_VERSION);
return proto;
}
void TransactionTracing::dump(std::string& result) const {
std::scoped_lock lock(mTraceLock);
- base::StringAppendF(&result,
- " queued transactions=%zu created layers=%zu handles=%zu states=%zu\n",
- mQueuedTransactions.size(), mCreatedLayers.size(), mLayerHandles.size(),
- mStartingStates.size());
+ base::StringAppendF(&result, " queued transactions=%zu created layers=%zu states=%zu\n",
+ mQueuedTransactions.size(), mCreatedLayers.size(), mStartingStates.size());
mBuffer.dump(result);
}
void TransactionTracing::addQueuedTransaction(const TransactionState& transaction) {
- proto::TransactionState* state =
- new proto::TransactionState(mLockfreeProtoParser.toProto(transaction));
+ proto::TransactionState* state = new proto::TransactionState(mProtoParser.toProto(transaction));
mTransactionQueue.push(state);
}
-TransactionTracing::CommittedTransactions&
-TransactionTracing::findOrCreateCommittedTransactionRecord(int64_t vsyncId) {
- for (auto& pendingTransaction : mPendingTransactions) {
- if (pendingTransaction.vsyncId == vsyncId) {
- return pendingTransaction;
- }
+void TransactionTracing::addCommittedTransactions(
+ int64_t vsyncId, nsecs_t commitTime, frontend::Update& newUpdate,
+ const display::DisplayMap<ui::LayerStack, frontend::DisplayInfo>& displayInfos,
+ bool displayInfoChanged) {
+ CommittedUpdates update;
+ update.vsyncId = vsyncId;
+ update.timestamp = commitTime;
+ update.transactionIds.reserve(newUpdate.transactions.size());
+ for (const auto& transaction : newUpdate.transactions) {
+ update.transactionIds.emplace_back(transaction.id);
}
-
- CommittedTransactions committedTransactions;
- committedTransactions.vsyncId = vsyncId;
- committedTransactions.timestamp = systemTime();
- mPendingTransactions.emplace_back(committedTransactions);
- return mPendingTransactions.back();
-}
-
-void TransactionTracing::onLayerAddedToDrawingState(int layerId, int64_t vsyncId) {
- CommittedTransactions& committedTransactions = findOrCreateCommittedTransactionRecord(vsyncId);
- committedTransactions.createdLayerIds.emplace_back(layerId);
-}
-
-void TransactionTracing::addCommittedTransactions(std::vector<TransactionState>& transactions,
- int64_t vsyncId) {
- CommittedTransactions& committedTransactions = findOrCreateCommittedTransactionRecord(vsyncId);
- committedTransactions.transactionIds.reserve(transactions.size());
- for (const auto& transaction : transactions) {
- committedTransactions.transactionIds.emplace_back(transaction.id);
+ update.displayInfoChanged = displayInfoChanged;
+ if (displayInfoChanged) {
+ update.displayInfos = displayInfos;
}
+ update.createdLayers = std::move(newUpdate.layerCreationArgs);
+ newUpdate.layerCreationArgs.clear();
+ update.destroyedLayerHandles.reserve(newUpdate.destroyedHandles.size());
+ for (uint32_t handle : newUpdate.destroyedHandles) {
+ update.destroyedLayerHandles.push_back(handle);
+ }
+ mPendingUpdates.emplace_back(update);
tryPushToTracingThread();
}
void TransactionTracing::loop() {
while (true) {
- std::vector<CommittedTransactions> committedTransactions;
- std::vector<int32_t> removedLayers;
+ std::vector<CommittedUpdates> committedUpdates;
+ std::vector<uint32_t> destroyedLayers;
{
std::unique_lock<std::mutex> lock(mMainThreadLock);
base::ScopedLockAssertion assumeLocked(mMainThreadLock);
mTransactionsAvailableCv.wait(lock, [&]() REQUIRES(mMainThreadLock) {
- return mDone || !mCommittedTransactions.empty();
+ return mDone || !mUpdates.empty();
});
if (mDone) {
- mCommittedTransactions.clear();
- mRemovedLayers.clear();
+ mUpdates.clear();
+ mDestroyedLayers.clear();
break;
}
- removedLayers = std::move(mRemovedLayers);
- mRemovedLayers.clear();
- committedTransactions = std::move(mCommittedTransactions);
- mCommittedTransactions.clear();
+ destroyedLayers = std::move(mDestroyedLayers);
+ mDestroyedLayers.clear();
+ committedUpdates = std::move(mUpdates);
+ mUpdates.clear();
} // unlock mMainThreadLock
- if (!committedTransactions.empty() || !removedLayers.empty()) {
- addEntry(committedTransactions, removedLayers);
+ if (!committedUpdates.empty() || !destroyedLayers.empty()) {
+ addEntry(committedUpdates, destroyedLayers);
}
}
}
-void TransactionTracing::addEntry(const std::vector<CommittedTransactions>& committedTransactions,
- const std::vector<int32_t>& removedLayers) {
+void TransactionTracing::addEntry(const std::vector<CommittedUpdates>& committedUpdates,
+ const std::vector<uint32_t>& destroyedLayers) {
ATRACE_CALL();
std::scoped_lock lock(mTraceLock);
std::vector<std::string> removedEntries;
@@ -222,59 +154,27 @@
while (auto incomingTransaction = mTransactionQueue.pop()) {
auto transaction = *incomingTransaction;
- int32_t layerCount = transaction.layer_changes_size();
- for (int i = 0; i < layerCount; i++) {
- auto layer = transaction.mutable_layer_changes(i);
- layer->set_layer_id(
- mProtoParser.mMapper->getLayerId(reinterpret_cast<BBinder*>(layer->layer_id())));
- if ((layer->what() & layer_state_t::eReparent) && layer->parent_id() != -1) {
- layer->set_parent_id(
- mProtoParser.mMapper->getLayerId(reinterpret_cast<BBinder*>(
- layer->parent_id())));
- }
-
- if ((layer->what() & layer_state_t::eRelativeLayerChanged) &&
- layer->relative_parent_id() != -1) {
- layer->set_relative_parent_id(
- mProtoParser.mMapper->getLayerId(reinterpret_cast<BBinder*>(
- layer->relative_parent_id())));
- }
-
- if (layer->has_window_info_handle() &&
- layer->window_info_handle().crop_layer_id() != -1) {
- auto input = layer->mutable_window_info_handle();
- input->set_crop_layer_id(
- mProtoParser.mMapper->getLayerId(reinterpret_cast<BBinder*>(
- input->crop_layer_id())));
- }
- }
mQueuedTransactions[incomingTransaction->transaction_id()] = transaction;
delete incomingTransaction;
}
- for (const CommittedTransactions& entry : committedTransactions) {
- entryProto.set_elapsed_realtime_nanos(entry.timestamp);
- entryProto.set_vsync_id(entry.vsyncId);
+ for (const CommittedUpdates& update : committedUpdates) {
+ entryProto.set_elapsed_realtime_nanos(update.timestamp);
+ entryProto.set_vsync_id(update.vsyncId);
entryProto.mutable_added_layers()->Reserve(
- static_cast<int32_t>(entry.createdLayerIds.size()));
+ static_cast<int32_t>(update.createdLayers.size()));
- for (const int32_t& id : entry.createdLayerIds) {
- auto it = mCreatedLayers.find(id);
- if (it != mCreatedLayers.end()) {
- entryProto.mutable_added_layers()->Add(std::move(it->second));
- mCreatedLayers.erase(it);
- } else {
- ALOGW("Could not created layer with id %d", id);
- }
+ for (const auto& args : update.createdLayers) {
+ entryProto.mutable_added_layers()->Add(std::move(mProtoParser.toProto(args)));
}
- entryProto.mutable_removed_layers()->Reserve(static_cast<int32_t>(removedLayers.size()));
- for (auto& removedLayer : removedLayers) {
- entryProto.mutable_removed_layers()->Add(removedLayer);
- mCreatedLayers.erase(removedLayer);
+ entryProto.mutable_destroyed_layers()->Reserve(
+ static_cast<int32_t>(destroyedLayers.size()));
+ for (auto& destroyedLayer : destroyedLayers) {
+ entryProto.mutable_destroyed_layers()->Add(destroyedLayer);
}
entryProto.mutable_transactions()->Reserve(
- static_cast<int32_t>(entry.transactionIds.size()));
- for (const uint64_t& id : entry.transactionIds) {
+ static_cast<int32_t>(update.transactionIds.size()));
+ for (const uint64_t& id : update.transactionIds) {
auto it = mQueuedTransactions.find(id);
if (it != mQueuedTransactions.end()) {
entryProto.mutable_transactions()->Add(std::move(it->second));
@@ -284,13 +184,21 @@
}
}
- entryProto.mutable_removed_layer_handles()->Reserve(
- static_cast<int32_t>(mRemovedLayerHandles.size()));
- for (auto& [handle, layerId] : mRemovedLayerHandles) {
- entryProto.mutable_removed_layer_handles()->Add(layerId);
- mLayerHandles.erase(handle);
+ entryProto.mutable_destroyed_layer_handles()->Reserve(
+ static_cast<int32_t>(update.destroyedLayerHandles.size()));
+ for (auto layerId : update.destroyedLayerHandles) {
+ entryProto.mutable_destroyed_layer_handles()->Add(layerId);
}
- mRemovedLayerHandles.clear();
+
+ entryProto.set_displays_changed(update.displayInfoChanged);
+ if (update.displayInfoChanged) {
+ entryProto.mutable_displays()->Reserve(
+ static_cast<int32_t>(update.displayInfos.size()));
+ for (auto& [layerStack, displayInfo] : update.displayInfos) {
+ entryProto.mutable_displays()->Add(
+ std::move(mProtoParser.toProto(displayInfo, layerStack.id)));
+ }
+ }
std::string serializedProto;
entryProto.SerializeToString(&serializedProto);
@@ -311,7 +219,7 @@
}
void TransactionTracing::flush(int64_t vsyncId) {
- while (!mPendingTransactions.empty() || !mPendingRemovedLayers.empty()) {
+ while (!mPendingUpdates.empty() || !mPendingDestroyedLayers.empty()) {
tryPushToTracingThread();
}
std::unique_lock<std::mutex> lock(mTraceLock);
@@ -325,54 +233,21 @@
});
}
-void TransactionTracing::onLayerAdded(BBinder* layerHandle, int layerId, const std::string& name,
- uint32_t flags, int parentId) {
- std::scoped_lock lock(mTraceLock);
- TracingLayerCreationArgs args{layerId, name, flags, parentId, -1 /* mirrorFromId */};
- if (mLayerHandles.find(layerHandle) != mLayerHandles.end()) {
- ALOGW("Duplicate handles found. %p", layerHandle);
- }
- mLayerHandles[layerHandle] = layerId;
- mCreatedLayers[layerId] = mProtoParser.toProto(args);
-}
-
-void TransactionTracing::onMirrorLayerAdded(BBinder* layerHandle, int layerId,
- const std::string& name, int mirrorFromId) {
- std::scoped_lock lock(mTraceLock);
- TracingLayerCreationArgs args{layerId, name, 0 /* flags */, -1 /* parentId */, mirrorFromId};
- if (mLayerHandles.find(layerHandle) != mLayerHandles.end()) {
- ALOGW("Duplicate handles found. %p", layerHandle);
- }
- mLayerHandles[layerHandle] = layerId;
- mCreatedLayers[layerId] = mProtoParser.toProto(args);
-}
-
void TransactionTracing::onLayerRemoved(int32_t layerId) {
- mPendingRemovedLayers.emplace_back(layerId);
+ mPendingDestroyedLayers.emplace_back(layerId);
tryPushToTracingThread();
}
-void TransactionTracing::onHandleRemoved(BBinder* layerHandle) {
- std::scoped_lock lock(mTraceLock);
- auto it = mLayerHandles.find(layerHandle);
- if (it == mLayerHandles.end()) {
- ALOGW("handle not found. %p", layerHandle);
- return;
- }
- mRemovedLayerHandles.emplace_back(layerHandle, it->second);
-}
-
void TransactionTracing::tryPushToTracingThread() {
// Try to acquire the lock from main thread.
if (mMainThreadLock.try_lock()) {
// We got the lock! Collect any pending transactions and continue.
- mCommittedTransactions.insert(mCommittedTransactions.end(),
- std::make_move_iterator(mPendingTransactions.begin()),
- std::make_move_iterator(mPendingTransactions.end()));
- mPendingTransactions.clear();
- mRemovedLayers.insert(mRemovedLayers.end(), mPendingRemovedLayers.begin(),
- mPendingRemovedLayers.end());
- mPendingRemovedLayers.clear();
+ mUpdates.insert(mUpdates.end(), std::make_move_iterator(mPendingUpdates.begin()),
+ std::make_move_iterator(mPendingUpdates.end()));
+ mPendingUpdates.clear();
+ mDestroyedLayers.insert(mDestroyedLayers.end(), mPendingDestroyedLayers.begin(),
+ mPendingDestroyedLayers.end());
+ mPendingDestroyedLayers.clear();
mTransactionsAvailableCv.notify_one();
mMainThreadLock.unlock();
} else {
@@ -394,24 +269,28 @@
// Merge layer states to starting transaction state.
for (const proto::TransactionState& transaction : removedEntry.transactions()) {
for (const proto::LayerState& layerState : transaction.layer_changes()) {
- auto it = mStartingStates.find((int32_t)layerState.layer_id());
+ auto it = mStartingStates.find(layerState.layer_id());
if (it == mStartingStates.end()) {
- ALOGW("Could not find layer id %d", (int32_t)layerState.layer_id());
+ ALOGW("Could not find layer id %d", layerState.layer_id());
continue;
}
mProtoParser.mergeFromProto(layerState, it->second);
}
}
- for (const int32_t removedLayerHandleId : removedEntry.removed_layer_handles()) {
- mRemovedLayerHandlesAtStart.insert(removedLayerHandleId);
+ for (const uint32_t destroyedLayerHandleId : removedEntry.destroyed_layer_handles()) {
+ mRemovedLayerHandlesAtStart.insert(destroyedLayerHandleId);
}
// Clean up stale starting states since the layer has been removed and the buffer does not
// contain any references to the layer.
- for (const int32_t removedLayerId : removedEntry.removed_layers()) {
- mStartingStates.erase(removedLayerId);
- mRemovedLayerHandlesAtStart.erase(removedLayerId);
+ for (const uint32_t destroyedLayerId : removedEntry.destroyed_layers()) {
+ mStartingStates.erase(destroyedLayerId);
+ mRemovedLayerHandlesAtStart.erase(destroyedLayerId);
+ }
+
+ if (removedEntry.displays_changed()) {
+ mProtoParser.fromProto(removedEntry.displays(), mStartingDisplayInfos);
}
}
@@ -434,10 +313,15 @@
transactionProto.set_post_time(mStartingTimestamp);
entryProto->mutable_transactions()->Add(std::move(transactionProto));
- entryProto->mutable_removed_layer_handles()->Reserve(
+ entryProto->mutable_destroyed_layer_handles()->Reserve(
static_cast<int32_t>(mRemovedLayerHandlesAtStart.size()));
- for (const int32_t removedLayerHandleId : mRemovedLayerHandlesAtStart) {
- entryProto->mutable_removed_layer_handles()->Add(removedLayerHandleId);
+ for (const uint32_t destroyedLayerHandleId : mRemovedLayerHandlesAtStart) {
+ entryProto->mutable_destroyed_layer_handles()->Add(destroyedLayerHandleId);
+ }
+
+ entryProto->mutable_displays()->Reserve(static_cast<int32_t>(mStartingDisplayInfos.size()));
+ for (auto& [layerStack, displayInfo] : mStartingDisplayInfos) {
+ entryProto->mutable_displays()->Add(mProtoParser.toProto(displayInfo, layerStack.id));
}
}
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.h b/services/surfaceflinger/Tracing/TransactionTracing.h
index ae01d3c..f27e7a9 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.h
+++ b/services/surfaceflinger/Tracing/TransactionTracing.h
@@ -25,8 +25,12 @@
#include <mutex>
#include <thread>
-#include "RingBuffer.h"
+#include "Display/DisplayMap.h"
+#include "FrontEnd/DisplayInfo.h"
+#include "FrontEnd/LayerCreationArgs.h"
+#include "FrontEnd/Update.h"
#include "LocklessStack.h"
+#include "RingBuffer.h"
#include "TransactionProtoParser.h"
using namespace android::surfaceflinger;
@@ -55,22 +59,22 @@
~TransactionTracing();
void addQueuedTransaction(const TransactionState&);
- void addCommittedTransactions(std::vector<TransactionState>& transactions, int64_t vsyncId);
+ void addCommittedTransactions(
+ int64_t vsyncId, nsecs_t commitTime, frontend::Update& update,
+ const display::DisplayMap<ui::LayerStack, frontend::DisplayInfo>& displayInfos,
+ bool displayInfoChanged);
status_t writeToFile(std::string filename = FILE_NAME);
void setBufferSize(size_t bufferSizeInBytes);
- void onLayerAdded(BBinder* layerHandle, int layerId, const std::string& name, uint32_t flags,
- int parentId);
- void onMirrorLayerAdded(BBinder* layerHandle, int layerId, const std::string& name,
- int mirrorFromId);
void onLayerRemoved(int layerId);
- void onHandleRemoved(BBinder* layerHandle);
- void onLayerAddedToDrawingState(int layerId, int64_t vsyncId);
void dump(std::string&) const;
static constexpr auto CONTINUOUS_TRACING_BUFFER_SIZE = 512 * 1024;
static constexpr auto ACTIVE_TRACING_BUFFER_SIZE = 100 * 1024 * 1024;
+ // version 1 - switching to support new frontend
+ static constexpr auto TRACING_VERSION = 1;
private:
friend class TransactionTracingTest;
+ friend class SurfaceFlinger;
static constexpr auto FILE_NAME = "/data/misc/wmtrace/transactions_trace.winscope";
@@ -83,16 +87,12 @@
LocklessStack<proto::TransactionState> mTransactionQueue;
nsecs_t mStartingTimestamp GUARDED_BY(mTraceLock);
std::unordered_map<int, proto::LayerCreationArgs> mCreatedLayers GUARDED_BY(mTraceLock);
- std::unordered_map<BBinder* /* layerHandle */, int32_t /* layerId */> mLayerHandles
+ std::map<uint32_t /* layerId */, TracingLayerState> mStartingStates GUARDED_BY(mTraceLock);
+ display::DisplayMap<ui::LayerStack, frontend::DisplayInfo> mStartingDisplayInfos
GUARDED_BY(mTraceLock);
- std::vector<std::pair<BBinder* /* layerHandle */, int32_t /* layerId */>> mRemovedLayerHandles
- GUARDED_BY(mTraceLock);
- std::map<int32_t /* layerId */, TracingLayerState> mStartingStates GUARDED_BY(mTraceLock);
- std::set<int32_t /* layerId */> mRemovedLayerHandlesAtStart GUARDED_BY(mTraceLock);
- TransactionProtoParser mProtoParser GUARDED_BY(mTraceLock);
- // Parses the transaction to proto without holding any tracing locks so we can generate proto
- // in the binder thread without any contention.
- TransactionProtoParser mLockfreeProtoParser;
+
+ std::set<uint32_t /* layerId */> mRemovedLayerHandlesAtStart GUARDED_BY(mTraceLock);
+ TransactionProtoParser mProtoParser;
// We do not want main thread to block so main thread will try to acquire mMainThreadLock,
// otherwise will push data to temporary container.
@@ -101,27 +101,29 @@
bool mDone GUARDED_BY(mMainThreadLock) = false;
std::condition_variable mTransactionsAvailableCv;
std::condition_variable mTransactionsAddedToBufferCv;
- struct CommittedTransactions {
+ struct CommittedUpdates {
std::vector<uint64_t> transactionIds;
- std::vector<int32_t> createdLayerIds;
+ std::vector<LayerCreationArgs> createdLayers;
+ std::vector<uint32_t> destroyedLayerHandles;
+ bool displayInfoChanged;
+ display::DisplayMap<ui::LayerStack, frontend::DisplayInfo> displayInfos;
int64_t vsyncId;
int64_t timestamp;
};
- std::vector<CommittedTransactions> mCommittedTransactions GUARDED_BY(mMainThreadLock);
- std::vector<CommittedTransactions> mPendingTransactions; // only accessed by main thread
+ std::vector<CommittedUpdates> mUpdates GUARDED_BY(mMainThreadLock);
+ std::vector<CommittedUpdates> mPendingUpdates; // only accessed by main thread
- std::vector<int32_t /* layerId */> mRemovedLayers GUARDED_BY(mMainThreadLock);
- std::vector<int32_t /* layerId */> mPendingRemovedLayers; // only accessed by main thread
+ std::vector<uint32_t /* layerId */> mDestroyedLayers GUARDED_BY(mMainThreadLock);
+ std::vector<uint32_t /* layerId */> mPendingDestroyedLayers; // only accessed by main thread
proto::TransactionTraceFile createTraceFileProto() const;
void loop();
- void addEntry(const std::vector<CommittedTransactions>& committedTransactions,
- const std::vector<int32_t>& removedLayers) EXCLUDES(mTraceLock);
+ void addEntry(const std::vector<CommittedUpdates>& committedTransactions,
+ const std::vector<uint32_t>& removedLayers) EXCLUDES(mTraceLock);
int32_t getLayerIdLocked(const sp<IBinder>& layerHandle) REQUIRES(mTraceLock);
void tryPushToTracingThread() EXCLUDES(mMainThreadLock);
void addStartingStateToProtoLocked(proto::TransactionTraceFile& proto) REQUIRES(mTraceLock);
void updateStartingStateLocked(const proto::TransactionTraceEntry& entry) REQUIRES(mTraceLock);
- CommittedTransactions& findOrCreateCommittedTransactionRecord(int64_t vsyncId);
// TEST
// Wait until all the committed transactions for the specified vsync id are added to the buffer.
void flush(int64_t vsyncId) EXCLUDES(mMainThreadLock);
diff --git a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
index 31f4723..0a7101c 100644
--- a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
+++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
@@ -14,175 +14,31 @@
* limitations under the License.
*/
+#include <memory>
+#include <vector>
+#include "FrontEnd/LayerCreationArgs.h"
+#include "FrontEnd/RequestedLayerState.h"
+#include "Tracing/LayerTracing.h"
+#include "TransactionState.h"
+#include "cutils/properties.h"
#undef LOG_TAG
#define LOG_TAG "LayerTraceGenerator"
//#define LOG_NDEBUG 0
-#include <TestableSurfaceFlinger.h>
#include <Tracing/TransactionProtoParser.h>
-#include <binder/IPCThreadState.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
#include <gui/LayerState.h>
#include <log/log.h>
-#include <mock/MockEventThread.h>
#include <renderengine/ExternalTexture.h>
-#include <renderengine/mock/RenderEngine.h>
#include <utils/String16.h>
+#include <filesystem>
+#include <fstream>
#include <string>
+#include "LayerProtoHelper.h"
#include "LayerTraceGenerator.h"
namespace android {
-
-class Factory final : public surfaceflinger::Factory {
-public:
- ~Factory() = default;
-
- std::unique_ptr<HWComposer> createHWComposer(const std::string&) override { return nullptr; }
-
- std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
- Fps /*currentRefreshRate*/) override {
- return std::make_unique<scheduler::FakePhaseOffsets>();
- }
-
- sp<StartPropertySetThread> createStartPropertySetThread(
- bool /* timestampPropertyValue */) override {
- return sp<StartPropertySetThread>();
- }
-
- sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs& /* creationArgs */) override {
- return sp<DisplayDevice>();
- }
-
- sp<GraphicBuffer> createGraphicBuffer(uint32_t /* width */, uint32_t /* height */,
- PixelFormat /* format */, uint32_t /* layerCount */,
- uint64_t /* usage */,
- std::string /* requestorName */) override {
- return sp<GraphicBuffer>();
- }
-
- void createBufferQueue(sp<IGraphicBufferProducer>* /* outProducer */,
- sp<IGraphicBufferConsumer>* /* outConsumer */,
- bool /* consumerIsSurfaceFlinger */) override {}
-
- std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface(
- const sp<IGraphicBufferProducer>& /* producer */) override {
- return nullptr;
- }
-
- std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine() override {
- return compositionengine::impl::createCompositionEngine();
- }
-
- sp<Layer> createBufferStateLayer(const LayerCreationArgs& args) {
- return sp<Layer>::make(args);
- }
-
- sp<Layer> createEffectLayer(const LayerCreationArgs& args) { return sp<Layer>::make(args); }
-
- sp<LayerFE> createLayerFE(const std::string& layerName) { return sp<LayerFE>::make(layerName); }
-
- std::unique_ptr<FrameTracer> createFrameTracer() override {
- return std::make_unique<testing::NiceMock<mock::FrameTracer>>();
- }
-
- std::unique_ptr<frametimeline::FrameTimeline> createFrameTimeline(
- std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid = 0) override {
- return std::make_unique<testing::NiceMock<mock::FrameTimeline>>(timeStats,
- surfaceFlingerPid);
- }
-};
-
-class FakeExternalTexture : public renderengine::ExternalTexture {
- const sp<GraphicBuffer> mNullBuffer = nullptr;
- uint32_t mWidth;
- uint32_t mHeight;
- uint64_t mId;
- PixelFormat mPixelFormat;
- uint64_t mUsage;
-
-public:
- FakeExternalTexture(uint32_t width, uint32_t height, uint64_t id, PixelFormat pixelFormat,
- uint64_t usage)
- : mWidth(width), mHeight(height), mId(id), mPixelFormat(pixelFormat), mUsage(usage) {}
- const sp<GraphicBuffer>& getBuffer() const { return mNullBuffer; }
- bool hasSameBuffer(const renderengine::ExternalTexture& other) const override {
- return getId() == other.getId();
- }
- uint32_t getWidth() const override { return mWidth; }
- uint32_t getHeight() const override { return mHeight; }
- uint64_t getId() const override { return mId; }
- PixelFormat getPixelFormat() const override { return mPixelFormat; }
- uint64_t getUsage() const override { return mUsage; }
- ~FakeExternalTexture() = default;
-};
-
-class MockSurfaceFlinger : public SurfaceFlinger {
-public:
- MockSurfaceFlinger(Factory& factory)
- : SurfaceFlinger(factory, SurfaceFlinger::SkipInitialization) {}
- std::shared_ptr<renderengine::ExternalTexture> getExternalTextureFromBufferData(
- BufferData& bufferData, const char* /* layerName */,
- uint64_t /* transactionId */) override {
- return std::make_shared<FakeExternalTexture>(bufferData.getWidth(), bufferData.getHeight(),
- bufferData.getId(),
- bufferData.getPixelFormat(),
- bufferData.getUsage());
- };
-
- // b/220017192 migrate from transact codes to ISurfaceComposer apis
- void setLayerTracingFlags(int32_t flags) {
- Parcel data;
- Parcel reply;
- data.writeInterfaceToken(String16("android.ui.ISurfaceComposer"));
- data.writeInt32(flags);
- transact(1033, data, &reply, 0 /* flags */);
- }
-
- void setLayerTraceSize(int32_t sizeInKb) {
- Parcel data;
- Parcel reply;
- data.writeInterfaceToken(String16("android.ui.ISurfaceComposer"));
- data.writeInt32(sizeInKb);
- transact(1029, data, &reply, 0 /* flags */);
- }
-
- void startLayerTracing(int64_t traceStartTime) {
- Parcel data;
- Parcel reply;
- data.writeInterfaceToken(String16("android.ui.ISurfaceComposer"));
- data.writeInt32(1);
- data.writeInt64(traceStartTime);
- transact(1025, data, &reply, 0 /* flags */);
- }
-
- void stopLayerTracing(const char* tracePath) {
- Parcel data;
- Parcel reply;
- data.writeInterfaceToken(String16("android.ui.ISurfaceComposer"));
- data.writeInt32(2);
- data.writeCString(tracePath);
- transact(1025, data, &reply, 0 /* flags */);
- }
-};
-
-class TraceGenFlingerDataMapper : public TransactionProtoParser::FlingerDataMapper {
-public:
- std::unordered_map<int32_t /*layerId*/, sp<IBinder> /* handle */> mLayerHandles;
- sp<IBinder> getLayerHandle(int32_t layerId) const override {
- if (layerId == -1) {
- ALOGE("Error: Called with layer=%d", layerId);
- return nullptr;
- }
- auto it = mLayerHandles.find(layerId);
- if (it == mLayerHandles.end()) {
- ALOGE("Error: Could not find handle for layer=%d", layerId);
- return nullptr;
- }
- return it->second;
- }
-};
+using namespace ftl::flag_operators;
bool LayerTraceGenerator::generate(const proto::TransactionTraceFile& traceFile,
const char* outputLayersTracePath) {
@@ -191,82 +47,122 @@
return false;
}
- Factory factory;
- sp<MockSurfaceFlinger> flingerPtr = sp<MockSurfaceFlinger>::make(factory);
- TestableSurfaceFlinger flinger(flingerPtr);
- flinger.setupRenderEngine(
- std::make_unique<testing::NiceMock<renderengine::mock::RenderEngine>>());
- flinger.setupMockScheduler({.useNiceMock = true});
+ TransactionProtoParser parser(std::make_unique<TransactionProtoParser::FlingerDataMapper>());
- Hwc2::mock::Composer* composerPtr = new testing::NiceMock<Hwc2::mock::Composer>();
- flinger.setupComposer(std::unique_ptr<Hwc2::Composer>(composerPtr));
- flinger.mutableMaxRenderTargetSize() = 16384;
+ // frontend
+ frontend::LayerLifecycleManager lifecycleManager;
+ frontend::LayerHierarchyBuilder hierarchyBuilder{{}};
+ frontend::LayerSnapshotBuilder snapshotBuilder;
+ display::DisplayMap<ui::LayerStack, frontend::DisplayInfo> displayInfos;
- flingerPtr->setLayerTracingFlags(LayerTracing::TRACE_INPUT | LayerTracing::TRACE_BUFFERS);
- flingerPtr->setLayerTraceSize(512 * 1024); // 512MB buffer size
- flingerPtr->startLayerTracing(traceFile.entry(0).elapsed_realtime_nanos());
- std::unique_ptr<TraceGenFlingerDataMapper> mapper =
- std::make_unique<TraceGenFlingerDataMapper>();
- TraceGenFlingerDataMapper* dataMapper = mapper.get();
- TransactionProtoParser parser(std::move(mapper));
+ renderengine::ShadowSettings globalShadowSettings{.ambientColor = {1, 1, 1, 1}};
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.surface_flinger.supports_background_blur", value, "0");
+ bool supportsBlur = atoi(value);
+
+ LayerTracing layerTracing;
+ layerTracing.setTraceFlags(LayerTracing::TRACE_INPUT | LayerTracing::TRACE_BUFFERS);
+ layerTracing.setBufferSize(512 * 1024 * 1024); // 512MB buffer size
+ layerTracing.enable();
ALOGD("Generating %d transactions...", traceFile.entry_size());
for (int i = 0; i < traceFile.entry_size(); i++) {
+ // parse proto
proto::TransactionTraceEntry entry = traceFile.entry(i);
ALOGV(" Entry %04d/%04d for time=%" PRId64 " vsyncid=%" PRId64
" layers +%d -%d handles -%d transactions=%d",
i, traceFile.entry_size(), entry.elapsed_realtime_nanos(), entry.vsync_id(),
- entry.added_layers_size(), entry.removed_layers_size(),
- entry.removed_layer_handles_size(), entry.transactions_size());
+ entry.added_layers_size(), entry.destroyed_layers_size(),
+ entry.destroyed_layer_handles_size(), entry.transactions_size());
+ std::vector<std::unique_ptr<frontend::RequestedLayerState>> addedLayers;
+ addedLayers.reserve((size_t)entry.added_layers_size());
for (int j = 0; j < entry.added_layers_size(); j++) {
- // create layers
- TracingLayerCreationArgs tracingArgs;
- parser.fromProto(entry.added_layers(j), tracingArgs);
-
- gui::CreateSurfaceResult outResult;
- LayerCreationArgs args(flinger.flinger(), nullptr /* client */, tracingArgs.name,
- tracingArgs.flags, LayerMetadata(),
- std::make_optional<int32_t>(tracingArgs.layerId));
-
- if (tracingArgs.mirrorFromId == -1) {
- sp<IBinder> parentHandle = nullptr;
- if ((tracingArgs.parentId != -1) &&
- (dataMapper->mLayerHandles.find(tracingArgs.parentId) ==
- dataMapper->mLayerHandles.end())) {
- args.addToRoot = false;
- } else if (tracingArgs.parentId != -1) {
- parentHandle = dataMapper->getLayerHandle(tracingArgs.parentId);
- }
- flinger.createLayer(args, parentHandle, outResult);
- } else {
- sp<IBinder> mirrorFromHandle = dataMapper->getLayerHandle(tracingArgs.mirrorFromId);
- flinger.mirrorLayer(args, mirrorFromHandle, outResult);
- }
- LOG_ALWAYS_FATAL_IF(outResult.layerId != tracingArgs.layerId,
- "Could not create layer expected:%d actual:%d", tracingArgs.layerId,
- outResult.layerId);
- dataMapper->mLayerHandles[tracingArgs.layerId] = outResult.handle;
+ LayerCreationArgs args;
+ parser.fromProto(entry.added_layers(j), args);
+ addedLayers.emplace_back(std::make_unique<frontend::RequestedLayerState>(args));
}
+ std::vector<TransactionState> transactions;
+ transactions.reserve((size_t)entry.transactions_size());
for (int j = 0; j < entry.transactions_size(); j++) {
// apply transactions
TransactionState transaction = parser.fromProto(entry.transactions(j));
- flinger.setTransactionStateInternal(transaction);
+ transactions.emplace_back(std::move(transaction));
}
- const auto frameTime = TimePoint::fromNs(entry.elapsed_realtime_nanos());
- const auto vsyncId = VsyncId{entry.vsync_id()};
- flinger.commit(frameTime, vsyncId);
-
- for (int j = 0; j < entry.removed_layer_handles_size(); j++) {
- dataMapper->mLayerHandles.erase(entry.removed_layer_handles(j));
+ std::vector<uint32_t> destroyedHandles;
+ destroyedHandles.reserve((size_t)entry.destroyed_layer_handles_size());
+ for (int j = 0; j < entry.destroyed_layer_handles_size(); j++) {
+ destroyedHandles.push_back(entry.destroyed_layer_handles(j));
}
+
+ bool displayChanged = entry.displays_changed();
+ if (displayChanged) {
+ parser.fromProto(entry.displays(), displayInfos);
+ }
+
+ // apply updates
+ lifecycleManager.addLayers(std::move(addedLayers));
+ lifecycleManager.applyTransactions(transactions);
+ lifecycleManager.onHandlesDestroyed(destroyedHandles, /*ignoreUnknownHandles=*/true);
+
+ if (lifecycleManager.getGlobalChanges().test(
+ frontend::RequestedLayerState::Changes::Hierarchy)) {
+ hierarchyBuilder.update(lifecycleManager.getLayers(),
+ lifecycleManager.getDestroyedLayers());
+ }
+
+ frontend::LayerSnapshotBuilder::Args args{.root = hierarchyBuilder.getHierarchy(),
+ .layerLifecycleManager = lifecycleManager,
+ .displays = displayInfos,
+ .displayChanges = displayChanged,
+ .globalShadowSettings = globalShadowSettings,
+ .supportsBlur = supportsBlur,
+ .forceFullDamage = false,
+ .supportedLayerGenericMetadata = {},
+ .genericLayerMetadataKeyMap = {}};
+ snapshotBuilder.update(args);
+
+ bool visibleRegionsDirty = lifecycleManager.getGlobalChanges().any(
+ frontend::RequestedLayerState::Changes::VisibleRegion |
+ frontend::RequestedLayerState::Changes::Hierarchy |
+ frontend::RequestedLayerState::Changes::Visibility);
+
+ ALOGV(" layers:%04zu snapshots:%04zu changes:%s", lifecycleManager.getLayers().size(),
+ snapshotBuilder.getSnapshots().size(),
+ lifecycleManager.getGlobalChanges().string().c_str());
+
+ lifecycleManager.commitChanges();
+ // write layers trace
+ auto tracingFlags = LayerTracing::TRACE_INPUT | LayerTracing::TRACE_BUFFERS;
+ std::unordered_set<uint64_t> stackIdsToSkip;
+ if ((tracingFlags & LayerTracing::TRACE_VIRTUAL_DISPLAYS) == 0) {
+ for (const auto& displayInfo : displayInfos) {
+ if (displayInfo.second.isVirtual) {
+ stackIdsToSkip.insert(displayInfo.first.id);
+ }
+ }
+ }
+
+ const frontend::LayerHierarchy& root = hierarchyBuilder.getHierarchy();
+
+ LayersProto layersProto;
+ for (auto& [child, variant] : root.mChildren) {
+ if (variant != frontend::LayerHierarchy::Variant::Attached ||
+ stackIdsToSkip.find(child->getLayer()->layerStack.id) != stackIdsToSkip.end()) {
+ continue;
+ }
+ LayerProtoHelper::writeHierarchyToProto(layersProto, *child, snapshotBuilder, {},
+ tracingFlags);
+ }
+
+ auto displayProtos = LayerProtoHelper::writeDisplayInfoToProto(displayInfos);
+ layerTracing.notify(visibleRegionsDirty, entry.elapsed_realtime_nanos(), entry.vsync_id(),
+ &layersProto, {}, &displayProtos);
}
-
- flingerPtr->stopLayerTracing(outputLayersTracePath);
+ layerTracing.disable(outputLayersTracePath);
ALOGD("End of generating trace file. File written to %s", outputLayersTracePath);
- dataMapper->mLayerHandles.clear();
return true;
}
diff --git a/services/surfaceflinger/Tracing/tools/main.cpp b/services/surfaceflinger/Tracing/tools/main.cpp
index 9f9ae48..c440c19 100644
--- a/services/surfaceflinger/Tracing/tools/main.cpp
+++ b/services/surfaceflinger/Tracing/tools/main.cpp
@@ -53,9 +53,6 @@
ALOGD("Generating %s...", outputLayersTracePath);
std::cout << "Generating " << outputLayersTracePath << "\n";
- // sink any log spam from the stubbed surfaceflinger
- __android_log_set_logger([](const struct __android_log_message* /* log_message */) {});
-
if (!LayerTraceGenerator().generate(transactionTraceFile, outputLayersTracePath)) {
std::cout << "Error: Failed to generate layers trace " << outputLayersTracePath;
return -1;
diff --git a/services/surfaceflinger/TransactionState.h b/services/surfaceflinger/TransactionState.h
index 40d06a8..2daea25 100644
--- a/services/surfaceflinger/TransactionState.h
+++ b/services/surfaceflinger/TransactionState.h
@@ -20,6 +20,7 @@
#include <memory>
#include <mutex>
#include <vector>
+#include "FrontEnd/LayerCreationArgs.h"
#include "renderengine/ExternalTexture.h"
#include <gui/LayerState.h>
@@ -39,6 +40,10 @@
ResolvedComposerState() = default;
ResolvedComposerState(ComposerState&& source) { state = std::move(source.state); }
std::shared_ptr<renderengine::ExternalTexture> externalTexture;
+ uint32_t layerId = UNASSIGNED_LAYER_ID;
+ uint32_t parentId = UNASSIGNED_LAYER_ID;
+ uint32_t relativeParentId = UNASSIGNED_LAYER_ID;
+ uint32_t touchCropId = UNASSIGNED_LAYER_ID;
};
struct TransactionState {
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index f27f53b..6074bb7 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -402,9 +402,8 @@
SurfaceFlinger *flinger() { return mFlinger.get(); }
scheduler::TestableScheduler *scheduler() { return mScheduler; }
- // Allow reading display state without locking, as if called on the SF main thread.
- auto onInitializeDisplays() NO_THREAD_SAFETY_ANALYSIS {
- return mFlinger->onInitializeDisplays();
+ void initializeDisplays() {
+ FTL_FAKE_GUARD(kMainThreadContext, mFlinger->initializeDisplays());
}
void setGlobalShadowSettings(FuzzedDataProvider *fdp) {
@@ -453,8 +452,7 @@
LayersProto layersProto = mFlinger->dumpDrawingStateProto(fdp->ConsumeIntegral<uint32_t>());
mFlinger->dumpOffscreenLayersProto(layersProto);
- LayersTraceProto layersTraceProto{};
- mFlinger->dumpDisplayProto(layersTraceProto);
+ mFlinger->dumpDisplayProto();
result = fdp->ConsumeRandomLengthString().c_str();
mFlinger->dumpHwc(result);
@@ -542,7 +540,7 @@
mFlinger->createDisplay(String8(fdp->ConsumeRandomLengthString().c_str()),
fdp->ConsumeBool());
- onInitializeDisplays();
+ initializeDisplays();
mFlinger->getPhysicalDisplayToken(physicalDisplayId);
mFlinger->mStartPropertySetThread =
diff --git a/services/surfaceflinger/layerproto/transactions.proto b/services/surfaceflinger/layerproto/transactions.proto
index 4c6a9cf..2c4eb10 100644
--- a/services/surfaceflinger/layerproto/transactions.proto
+++ b/services/surfaceflinger/layerproto/transactions.proto
@@ -40,6 +40,7 @@
/* offset between real-time clock and elapsed time clock in nanoseconds.
Calculated as: systemTime(SYSTEM_TIME_REALTIME) - systemTime(SYSTEM_TIME_MONOTONIC) */
fixed64 real_to_elapsed_time_offset_nanos = 3;
+ uint32 version = 4;
}
message TransactionTraceEntry {
@@ -47,18 +48,47 @@
int64 vsync_id = 2;
repeated TransactionState transactions = 3;
repeated LayerCreationArgs added_layers = 4;
- repeated int32 removed_layers = 5;
+ repeated uint32 destroyed_layers = 5;
repeated DisplayState added_displays = 6;
repeated int32 removed_displays = 7;
- repeated int32 removed_layer_handles = 8;
+ repeated uint32 destroyed_layer_handles = 8;
+ bool displays_changed = 9;
+ repeated DisplayInfo displays = 10;
+}
+
+message DisplayInfo {
+ uint32 layer_stack = 1;
+ int32 display_id = 2;
+ int32 logical_width = 3;
+ int32 logical_height = 4;
+ Transform transform_inverse = 5;
+ Transform transform = 6;
+ bool receives_input = 7;
+ bool is_secure = 8;
+ bool is_primary = 9;
+ bool is_virtual = 10;
+ int32 rotation_flags = 11;
+ int32 transform_hint = 12;
+
}
message LayerCreationArgs {
- int32 layer_id = 1;
+ uint32 layer_id = 1;
string name = 2;
uint32 flags = 3;
- int32 parent_id = 4;
- int32 mirror_from_id = 5;
+ uint32 parent_id = 4;
+ uint32 mirror_from_id = 5;
+ bool add_to_root = 6;
+ uint32 layer_stack_to_mirror = 7;
+}
+
+message Transform {
+ float dsdx = 1;
+ float dtdx = 2;
+ float dtdy = 3;
+ float dsdy = 4;
+ float tx = 5;
+ float ty = 6;
}
message TransactionState {
@@ -74,7 +104,7 @@
// Keep insync with layer_state_t
message LayerState {
- int64 layer_id = 1;
+ uint32 layer_id = 1;
// Changes are split into ChangesLsb and ChangesMsb. First 32 bits are in ChangesLsb
// and the next 32 bits are in ChangesMsb. This is needed because enums have to be
// 32 bits and there's no nice way to put 64bit constants into .proto files.
@@ -164,8 +194,8 @@
Matrix22 matrix = 11;
float corner_radius = 12;
uint32 background_blur_radius = 13;
- int64 parent_id = 14;
- int64 relative_parent_id = 15;
+ uint32 parent_id = 14;
+ uint32 relative_parent_id = 15;
float alpha = 16;
message Color3 {
@@ -220,14 +250,6 @@
ColorTransformProto color_transform = 25;
repeated BlurRegion blur_regions = 26;
- message Transform {
- float dsdx = 1;
- float dtdx = 2;
- float dtdy = 3;
- float dsdy = 4;
- float tx = 5;
- float ty = 6;
- }
message WindowInfo {
uint32 layout_params_flags = 1;
int32 layout_params_type = 2;
@@ -236,7 +258,7 @@
bool focusable = 5;
bool has_wallpaper = 6;
float global_scale_factor = 7;
- int64 crop_layer_id = 8;
+ uint32 crop_layer_id = 8;
bool replace_touchable_region_with_crop = 9;
RectProto touchable_region_crop = 10;
Transform transform = 11;
diff --git a/services/surfaceflinger/tests/tracing/testdata/layers_trace_boot.winscope b/services/surfaceflinger/tests/tracing/testdata/layers_trace_boot.winscope
index 9e4005c..296d2fd 100644
--- a/services/surfaceflinger/tests/tracing/testdata/layers_trace_boot.winscope
+++ b/services/surfaceflinger/tests/tracing/testdata/layers_trace_boot.winscope
Binary files differ
diff --git a/services/surfaceflinger/tests/tracing/testdata/layers_trace_nodisplayfound.winscope b/services/surfaceflinger/tests/tracing/testdata/layers_trace_nodisplayfound.winscope
index 16a91ee..ae54415 100644
--- a/services/surfaceflinger/tests/tracing/testdata/layers_trace_nodisplayfound.winscope
+++ b/services/surfaceflinger/tests/tracing/testdata/layers_trace_nodisplayfound.winscope
Binary files differ
diff --git a/services/surfaceflinger/tests/tracing/testdata/transactions_trace_boot.winscope b/services/surfaceflinger/tests/tracing/testdata/transactions_trace_boot.winscope
index 8356ae7..8d03df4 100644
--- a/services/surfaceflinger/tests/tracing/testdata/transactions_trace_boot.winscope
+++ b/services/surfaceflinger/tests/tracing/testdata/transactions_trace_boot.winscope
Binary files differ
diff --git a/services/surfaceflinger/tests/tracing/testdata/transactions_trace_nodisplayfound.winscope b/services/surfaceflinger/tests/tracing/testdata/transactions_trace_nodisplayfound.winscope
index cd62ab8..022861c 100644
--- a/services/surfaceflinger/tests/tracing/testdata/transactions_trace_nodisplayfound.winscope
+++ b/services/surfaceflinger/tests/tracing/testdata/transactions_trace_nodisplayfound.winscope
Binary files differ
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 012a4ad..df3ffd2 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -107,9 +107,9 @@
"SurfaceFlinger_GetDisplayNativePrimariesTest.cpp",
"SurfaceFlinger_HdrOutputControlTest.cpp",
"SurfaceFlinger_HotplugTest.cpp",
+ "SurfaceFlinger_InitializeDisplaysTest.cpp",
"SurfaceFlinger_MultiDisplayPacesetterTest.cpp",
"SurfaceFlinger_NotifyPowerBoostTest.cpp",
- "SurfaceFlinger_OnInitializeDisplaysTest.cpp",
"SurfaceFlinger_PowerHintTest.cpp",
"SurfaceFlinger_SetDisplayStateTest.cpp",
"SurfaceFlinger_SetPowerModeInternalTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index abd7789..d26ef3c 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -489,7 +489,7 @@
auto displayFrame0 = getDisplayFrame(0);
EXPECT_EQ(displayFrame0->getActuals().presentTime, 59);
- EXPECT_EQ(displayFrame0->getJankType(), JankType::Unknown);
+ EXPECT_EQ(displayFrame0->getJankType(), JankType::Unknown | JankType::DisplayHAL);
EXPECT_EQ(surfaceFrame1->getActuals().presentTime, -1);
EXPECT_EQ(surfaceFrame1->getJankType(), JankType::Unknown);
}
@@ -2259,6 +2259,7 @@
mFrameTimeline->setSfWakeUp(sfToken3, 72, Fps::fromPeriodNsecs(11));
mFrameTimeline->setSfPresent(80, validPresentFence);
+ erroneousPresentFence2->signalForTest(2);
validPresentFence->signalForTest(80);
addEmptyDisplayFrame();
@@ -2268,14 +2269,14 @@
EXPECT_EQ(displayFrame->getActuals().presentTime, 26);
EXPECT_EQ(displayFrame->getFramePresentMetadata(), FramePresentMetadata::UnknownPresent);
EXPECT_EQ(displayFrame->getFrameReadyMetadata(), FrameReadyMetadata::UnknownFinish);
- EXPECT_EQ(displayFrame->getJankType(), JankType::Unknown);
+ EXPECT_EQ(displayFrame->getJankType(), JankType::Unknown | JankType::DisplayHAL);
}
{
auto displayFrame = getDisplayFrame(1);
EXPECT_EQ(displayFrame->getActuals().presentTime, 60);
EXPECT_EQ(displayFrame->getFramePresentMetadata(), FramePresentMetadata::UnknownPresent);
EXPECT_EQ(displayFrame->getFrameReadyMetadata(), FrameReadyMetadata::UnknownFinish);
- EXPECT_EQ(displayFrame->getJankType(), JankType::Unknown);
+ EXPECT_EQ(displayFrame->getJankType(), JankType::Unknown | JankType::DisplayHAL);
}
{
auto displayFrame = getDisplayFrame(2);
diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp
index 77dc868..ddf3363 100644
--- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp
@@ -17,12 +17,9 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-#include "FrontEnd/LayerHandle.h"
#include "FrontEnd/LayerHierarchy.h"
#include "FrontEnd/LayerLifecycleManager.h"
-#include "Layer.h"
#include "LayerHierarchyTest.h"
-#include "gui/SurfaceComposerClient.h"
#define UPDATE_AND_VERIFY(HIERARCHY) \
({ \
@@ -207,7 +204,8 @@
reparentRelativeLayer(11, 2);
UPDATE_AND_VERIFY(hierarchyBuilder);
- reparentRelativeLayer(11, UNASSIGNED_LAYER_ID);
+ // This calls setLayer
+ removeRelativeZ(11);
UPDATE_AND_VERIFY(hierarchyBuilder);
std::vector<uint32_t> expectedTraversalPath = {1, 11, 111, 12, 121, 122, 1221, 13, 2};
@@ -418,7 +416,7 @@
EXPECT_EQ(getTraversalPath(hierarchyBuilder.getOffscreenHierarchy()), expectedTraversalPath);
// remove relative parent so layer becomes onscreen again
- reparentRelativeLayer(11, UNASSIGNED_LAYER_ID);
+ removeRelativeZ(11);
UPDATE_AND_VERIFY(hierarchyBuilder);
expectedTraversalPath = {1, 11, 111, 12, 121, 122, 1221, 13};
diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
index b9a6159..5b3c7ef 100644
--- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
+++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
@@ -17,11 +17,10 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-#include "FrontEnd/LayerHandle.h"
+#include "Client.h" // temporarily needed for LayerCreationArgs
+#include "FrontEnd/LayerCreationArgs.h"
#include "FrontEnd/LayerHierarchy.h"
#include "FrontEnd/LayerLifecycleManager.h"
-#include "Layer.h"
-#include "gui/SurfaceComposerClient.h"
namespace android::surfaceflinger::frontend {
@@ -51,20 +50,21 @@
createLayer(1221, 122);
}
- LayerCreationArgs createArgs(uint32_t id, bool canBeRoot, wp<IBinder> parent,
- wp<IBinder> mirror) {
- LayerCreationArgs args(nullptr, nullptr, "testlayer", 0, {}, std::make_optional(id));
+ LayerCreationArgs createArgs(uint32_t id, bool canBeRoot, uint32_t parentId,
+ uint32_t layerIdToMirror) {
+ LayerCreationArgs args(std::make_optional(id));
+ args.name = "testlayer";
args.addToRoot = canBeRoot;
- args.parentHandle = parent;
- args.mirrorLayerHandle = mirror;
+ args.parentId = parentId;
+ args.layerIdToMirror = layerIdToMirror;
return args;
}
- LayerCreationArgs createDisplayMirrorArgs(uint32_t id, ui::LayerStack layerStack) {
- LayerCreationArgs args(nullptr, nullptr, "testlayer", 0, {}, std::make_optional(id));
+ LayerCreationArgs createDisplayMirrorArgs(uint32_t id, ui::LayerStack layerStackToMirror) {
+ LayerCreationArgs args(std::make_optional(id));
+ args.name = "testlayer";
args.addToRoot = true;
- args.parentHandle.clear();
- args.layerStackToMirror = layerStack;
+ args.layerStackToMirror = layerStackToMirror;
return args;
}
@@ -90,17 +90,14 @@
}
virtual void createRootLayer(uint32_t id) {
- sp<LayerHandle> handle = sp<LayerHandle>::make(id);
- mHandles[id] = handle;
std::vector<std::unique_ptr<RequestedLayerState>> layers;
layers.emplace_back(std::make_unique<RequestedLayerState>(
- createArgs(/*id=*/id, /*canBeRoot=*/true, /*parent=*/nullptr, /*mirror=*/nullptr)));
+ createArgs(/*id=*/id, /*canBeRoot=*/true, /*parent=*/UNASSIGNED_LAYER_ID,
+ /*mirror=*/UNASSIGNED_LAYER_ID)));
mLifecycleManager.addLayers(std::move(layers));
}
void createDisplayMirrorLayer(uint32_t id, ui::LayerStack layerStack) {
- sp<LayerHandle> handle = sp<LayerHandle>::make(id);
- mHandles[id] = handle;
std::vector<std::unique_ptr<RequestedLayerState>> layers;
layers.emplace_back(std::make_unique<RequestedLayerState>(
createDisplayMirrorArgs(/*id=*/id, layerStack)));
@@ -108,62 +105,56 @@
}
virtual void createLayer(uint32_t id, uint32_t parentId) {
- sp<LayerHandle> handle = sp<LayerHandle>::make(id);
- mHandles[id] = handle;
std::vector<std::unique_ptr<RequestedLayerState>> layers;
layers.emplace_back(std::make_unique<RequestedLayerState>(
- createArgs(/*id=*/id, /*canBeRoot=*/false, /*parent=*/mHandles[parentId],
- /*mirror=*/nullptr)));
+ createArgs(/*id=*/id, /*canBeRoot=*/false, /*parent=*/parentId,
+ /*mirror=*/UNASSIGNED_LAYER_ID)));
mLifecycleManager.addLayers(std::move(layers));
}
- void reparentLayer(uint32_t id, uint32_t newParentId) {
+ std::vector<TransactionState> reparentLayerTransaction(uint32_t id, uint32_t newParentId) {
std::vector<TransactionState> transactions;
transactions.emplace_back();
transactions.back().states.push_back({});
-
- if (newParentId == UNASSIGNED_LAYER_ID) {
- transactions.back().states.front().state.parentSurfaceControlForChild = nullptr;
- } else {
- auto parentHandle = mHandles[newParentId];
- transactions.back().states.front().state.parentSurfaceControlForChild =
- sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(), parentHandle,
- static_cast<int32_t>(newParentId), "Test");
- }
+ transactions.back().states.front().parentId = newParentId;
transactions.back().states.front().state.what = layer_state_t::eReparent;
- transactions.back().states.front().state.surface = mHandles[id];
- mLifecycleManager.applyTransactions(transactions);
+ transactions.back().states.front().relativeParentId = UNASSIGNED_LAYER_ID;
+ transactions.back().states.front().layerId = id;
+ return transactions;
+ }
+
+ void reparentLayer(uint32_t id, uint32_t newParentId) {
+ mLifecycleManager.applyTransactions(reparentLayerTransaction(id, newParentId));
+ }
+
+ std::vector<TransactionState> relativeLayerTransaction(uint32_t id, uint32_t relativeParentId) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+ transactions.back().states.front().relativeParentId = relativeParentId;
+ transactions.back().states.front().state.what = layer_state_t::eRelativeLayerChanged;
+ transactions.back().states.front().layerId = id;
+ return transactions;
}
void reparentRelativeLayer(uint32_t id, uint32_t relativeParentId) {
+ mLifecycleManager.applyTransactions(relativeLayerTransaction(id, relativeParentId));
+ }
+
+ void removeRelativeZ(uint32_t id) {
std::vector<TransactionState> transactions;
transactions.emplace_back();
transactions.back().states.push_back({});
-
- if (relativeParentId == UNASSIGNED_LAYER_ID) {
- transactions.back().states.front().state.what = layer_state_t::eLayerChanged;
- } else {
- auto parentHandle = mHandles[relativeParentId];
- transactions.back().states.front().state.relativeLayerSurfaceControl =
- sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(), parentHandle,
- static_cast<int32_t>(relativeParentId), "test");
- transactions.back().states.front().state.what = layer_state_t::eRelativeLayerChanged;
- }
- transactions.back().states.front().state.surface = mHandles[id];
+ transactions.back().states.front().state.what = layer_state_t::eLayerChanged;
+ transactions.back().states.front().layerId = id;
mLifecycleManager.applyTransactions(transactions);
}
- virtual void mirrorLayer(uint32_t id, uint32_t parent, uint32_t layerToMirror) {
- auto parentHandle = (parent == UNASSIGNED_LAYER_ID) ? nullptr : mHandles[parent];
- auto mirrorHandle =
- (layerToMirror == UNASSIGNED_LAYER_ID) ? nullptr : mHandles[layerToMirror];
-
- sp<LayerHandle> handle = sp<LayerHandle>::make(id);
- mHandles[id] = handle;
+ virtual void mirrorLayer(uint32_t id, uint32_t parentId, uint32_t layerIdToMirror) {
std::vector<std::unique_ptr<RequestedLayerState>> layers;
layers.emplace_back(std::make_unique<RequestedLayerState>(
- createArgs(/*id=*/id, /*canBeRoot=*/false, /*parent=*/parentHandle,
- /*mirror=*/mHandles[layerToMirror])));
+ createArgs(/*id=*/id, /*canBeRoot=*/false, /*parent=*/parentId,
+ /*mirror=*/layerIdToMirror)));
mLifecycleManager.addLayers(std::move(layers));
}
@@ -173,7 +164,7 @@
transactions.back().states.push_back({});
transactions.back().states.front().state.what = layer_state_t::eBackgroundColorChanged;
transactions.back().states.front().state.bgColor.a = alpha;
- transactions.back().states.front().state.surface = mHandles[id];
+ transactions.back().states.front().layerId = id;
mLifecycleManager.applyTransactions(transactions);
}
@@ -196,16 +187,19 @@
mLifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy));
}
- void setZ(uint32_t id, int32_t z) {
+ std::vector<TransactionState> setZTransaction(uint32_t id, int32_t z) {
std::vector<TransactionState> transactions;
transactions.emplace_back();
transactions.back().states.push_back({});
transactions.back().states.front().state.what = layer_state_t::eLayerChanged;
- transactions.back().states.front().state.surface = mHandles[id];
- transactions.back().states.front().state.layerId = static_cast<int32_t>(id);
+ transactions.back().states.front().layerId = id;
transactions.back().states.front().state.z = z;
- mLifecycleManager.applyTransactions(transactions);
+ return transactions;
+ }
+
+ void setZ(uint32_t id, int32_t z) {
+ mLifecycleManager.applyTransactions(setZTransaction(id, z));
}
void setCrop(uint32_t id, const Rect& crop) {
@@ -214,8 +208,7 @@
transactions.back().states.push_back({});
transactions.back().states.front().state.what = layer_state_t::eCropChanged;
- transactions.back().states.front().state.surface = mHandles[id];
- transactions.back().states.front().state.layerId = static_cast<int32_t>(id);
+ transactions.back().states.front().layerId = id;
transactions.back().states.front().state.crop = crop;
mLifecycleManager.applyTransactions(transactions);
}
@@ -228,8 +221,7 @@
transactions.back().states.front().state.what = layer_state_t::eFlagsChanged;
transactions.back().states.front().state.flags = flags;
transactions.back().states.front().state.mask = mask;
- transactions.back().states.front().state.surface = mHandles[id];
- transactions.back().states.front().state.layerId = static_cast<int32_t>(id);
+ transactions.back().states.front().layerId = id;
mLifecycleManager.applyTransactions(transactions);
}
@@ -239,8 +231,7 @@
transactions.back().states.push_back({});
transactions.back().states.front().state.what = layer_state_t::eAlphaChanged;
- transactions.back().states.front().state.surface = mHandles[id];
- transactions.back().states.front().state.layerId = static_cast<int32_t>(id);
+ transactions.back().states.front().layerId = id;
transactions.back().states.front().state.color.a = static_cast<half>(alpha);
mLifecycleManager.applyTransactions(transactions);
}
@@ -257,8 +248,7 @@
transactions.back().states.push_back({});
transactions.back().states.front().state.what = layer_state_t::eColorChanged;
transactions.back().states.front().state.color.rgb = rgb;
- transactions.back().states.front().state.surface = mHandles[id];
- transactions.back().states.front().state.layerId = static_cast<int32_t>(id);
+ transactions.back().states.front().layerId = id;
mLifecycleManager.applyTransactions(transactions);
}
@@ -268,8 +258,7 @@
transactions.back().states.push_back({});
transactions.back().states.front().state.what = layer_state_t::eLayerStackChanged;
- transactions.back().states.front().state.surface = mHandles[id];
- transactions.back().states.front().state.layerId = static_cast<int32_t>(id);
+ transactions.back().states.front().layerId = id;
transactions.back().states.front().state.layerStack = ui::LayerStack::fromValue(layerStack);
mLifecycleManager.applyTransactions(transactions);
}
@@ -280,8 +269,7 @@
transactions.back().states.push_back({});
transactions.back().states.front().state.what = layer_state_t::eInputInfoChanged;
- transactions.back().states.front().state.surface = mHandles[id];
- transactions.back().states.front().state.layerId = static_cast<int32_t>(id);
+ transactions.back().states.front().layerId = id;
transactions.back().states.front().state.windowInfoHandle =
sp<gui::WindowInfoHandle>::make();
auto inputInfo = transactions.back().states.front().state.windowInfoHandle->editInfo();
@@ -291,7 +279,6 @@
}
LayerLifecycleManager mLifecycleManager;
- std::unordered_map<uint32_t, sp<LayerHandle>> mHandles;
};
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp b/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp
index 99c1d23..14b8e4b 100644
--- a/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp
@@ -17,25 +17,14 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-#include "FrontEnd/LayerHandle.h"
#include "FrontEnd/LayerLifecycleManager.h"
-#include "Layer.h"
-#include "gui/SurfaceComposerClient.h"
+#include "LayerHierarchyTest.h"
+#include "TransactionState.h"
using namespace android::surfaceflinger;
namespace android::surfaceflinger::frontend {
-namespace {
-LayerCreationArgs createArgs(uint32_t id, bool canBeRoot, wp<IBinder> parent, wp<IBinder> mirror) {
- LayerCreationArgs args(nullptr, nullptr, "testlayer", 0, {}, std::make_optional(id));
- args.addToRoot = canBeRoot;
- args.parentHandle = parent;
- args.mirrorLayerHandle = mirror;
- return args;
-}
-} // namespace
-
// To run test:
/**
mp :libsurfaceflinger_unittest && adb sync; adb shell \
@@ -66,69 +55,24 @@
std::unordered_set<uint32_t> mActualLayersDestroyed;
};
-class LayerLifecycleManagerTest : public testing::Test {
+class LayerLifecycleManagerTest : public LayerHierarchyTestBase {
protected:
std::unique_ptr<RequestedLayerState> rootLayer(uint32_t id) {
- return std::make_unique<RequestedLayerState>(
- createArgs(/*id=*/id, /*canBeRoot=*/true, /*parent=*/nullptr, /*mirror=*/nullptr));
+ return std::make_unique<RequestedLayerState>(createArgs(/*id=*/id, /*canBeRoot=*/true,
+ /*parent=*/UNASSIGNED_LAYER_ID,
+ /*mirror=*/UNASSIGNED_LAYER_ID));
}
std::unique_ptr<RequestedLayerState> childLayer(uint32_t id, uint32_t parentId) {
- mHandles[parentId] = sp<LayerHandle>::make(parentId);
return std::make_unique<RequestedLayerState>(createArgs(/*id=*/id, /*canBeRoot=*/false,
- /*parent=*/mHandles[parentId],
- /*mirror=*/nullptr));
- }
-
- TransactionState reparentLayer(uint32_t id, uint32_t newParentId) {
- TransactionState transaction;
- transaction.states.push_back({});
-
- if (newParentId == UNASSIGNED_LAYER_ID) {
- transaction.states.front().state.parentSurfaceControlForChild = nullptr;
- } else {
- transaction.states.front().state.parentSurfaceControlForChild =
- sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(),
- sp<LayerHandle>::make(newParentId),
- static_cast<int32_t>(newParentId), "Test");
- }
- transaction.states.front().state.what = layer_state_t::eReparent;
- transaction.states.front().state.surface = sp<LayerHandle>::make(id);
- return transaction;
- }
-
- TransactionState setLayer(uint32_t id, int32_t z) {
- TransactionState transaction;
- transaction.states.push_back({});
- transaction.states.front().state.z = z;
- transaction.states.front().state.what = layer_state_t::eLayerChanged;
- transaction.states.front().state.surface = sp<LayerHandle>::make(id);
- return transaction;
- }
-
- TransactionState makeRelative(uint32_t id, uint32_t relativeParentId) {
- TransactionState transaction;
- transaction.states.push_back({});
-
- if (relativeParentId == UNASSIGNED_LAYER_ID) {
- transaction.states.front().state.relativeLayerSurfaceControl = nullptr;
- } else {
- transaction.states.front().state.relativeLayerSurfaceControl =
- sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(),
- sp<LayerHandle>::make(relativeParentId),
- static_cast<int32_t>(relativeParentId), "Test");
- }
- transaction.states.front().state.what = layer_state_t::eRelativeLayerChanged;
- transaction.states.front().state.surface = sp<LayerHandle>::make(id);
- return transaction;
+ parentId,
+ /*mirror=*/UNASSIGNED_LAYER_ID));
}
RequestedLayerState* getRequestedLayerState(LayerLifecycleManager& lifecycleManager,
uint32_t layerId) {
return lifecycleManager.getLayerFromId(layerId);
}
-
- std::unordered_map<uint32_t, sp<LayerHandle>> mHandles;
};
TEST_F(LayerLifecycleManagerTest, addLayers) {
@@ -153,16 +97,7 @@
std::vector<std::unique_ptr<RequestedLayerState>> layers;
layers.emplace_back(rootLayer(1));
lifecycleManager.addLayers(std::move(layers));
-
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
- transactions.back().states.front().state.z = 2;
- transactions.back().states.front().state.what = layer_state_t::eLayerChanged;
- sp<LayerHandle> handle = sp<LayerHandle>::make(1u);
- transactions.back().states.front().state.surface = handle;
- lifecycleManager.applyTransactions(transactions);
- transactions.clear();
+ lifecycleManager.applyTransactions(setZTransaction(1, 2));
auto& managedLayers = lifecycleManager.getLayers();
ASSERT_EQ(managedLayers.size(), 1u);
@@ -177,11 +112,12 @@
EXPECT_FALSE(managedLayers.front()->changes.test(RequestedLayerState::Changes::Z));
// apply transactions that do not affect the hierarchy
+ std::vector<TransactionState> transactions;
transactions.emplace_back();
transactions.back().states.push_back({});
transactions.back().states.front().state.backgroundBlurRadius = 22;
transactions.back().states.front().state.what = layer_state_t::eBackgroundBlurRadiusChanged;
- transactions.back().states.front().state.surface = handle;
+ transactions.back().states.front().layerId = 1;
lifecycleManager.applyTransactions(transactions);
EXPECT_FALSE(lifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy));
lifecycleManager.commitChanges();
@@ -232,7 +168,7 @@
listener->expectLayersAdded({1, 2, 3});
listener->expectLayersDestroyed({});
- lifecycleManager.applyTransactions({reparentLayer(3, UNASSIGNED_LAYER_ID)});
+ lifecycleManager.applyTransactions(reparentLayerTransaction(3, UNASSIGNED_LAYER_ID));
lifecycleManager.commitChanges();
listener->expectLayersAdded({});
listener->expectLayersDestroyed({});
@@ -257,7 +193,7 @@
listener->expectLayersAdded({1, 2, 3, 4});
listener->expectLayersDestroyed({});
- lifecycleManager.applyTransactions({reparentLayer(3, UNASSIGNED_LAYER_ID)});
+ lifecycleManager.applyTransactions(reparentLayerTransaction(3, UNASSIGNED_LAYER_ID));
lifecycleManager.onHandlesDestroyed({3});
lifecycleManager.commitChanges();
listener->expectLayersAdded({});
@@ -278,7 +214,7 @@
listener->expectLayersAdded({1, 2, 3, 4});
listener->expectLayersDestroyed({});
- lifecycleManager.applyTransactions({reparentLayer(3, UNASSIGNED_LAYER_ID)});
+ lifecycleManager.applyTransactions(reparentLayerTransaction(3, UNASSIGNED_LAYER_ID));
lifecycleManager.onHandlesDestroyed({3, 4});
lifecycleManager.commitChanges();
listener->expectLayersAdded({});
@@ -300,9 +236,9 @@
listener->expectLayersAdded({1, 2, 3, 4});
listener->expectLayersDestroyed({});
- lifecycleManager.applyTransactions({makeRelative(4, 1)});
+ lifecycleManager.applyTransactions(relativeLayerTransaction(4, 1));
EXPECT_TRUE(getRequestedLayerState(lifecycleManager, 4)->isRelativeOf);
- lifecycleManager.applyTransactions({reparentLayer(4, 2)});
+ lifecycleManager.applyTransactions(reparentLayerTransaction(4, 2));
EXPECT_TRUE(getRequestedLayerState(lifecycleManager, 4)->isRelativeOf);
lifecycleManager.commitChanges();
@@ -325,9 +261,9 @@
listener->expectLayersAdded({1, 2, 3, 4});
listener->expectLayersDestroyed({});
- lifecycleManager.applyTransactions({makeRelative(4, 1)});
+ lifecycleManager.applyTransactions(relativeLayerTransaction(4, 1));
EXPECT_TRUE(getRequestedLayerState(lifecycleManager, 4)->isRelativeOf);
- lifecycleManager.applyTransactions({reparentLayer(4, UNASSIGNED_LAYER_ID)});
+ lifecycleManager.applyTransactions(reparentLayerTransaction(4, UNASSIGNED_LAYER_ID));
EXPECT_FALSE(getRequestedLayerState(lifecycleManager, 4)->isRelativeOf);
lifecycleManager.commitChanges();
@@ -350,9 +286,9 @@
listener->expectLayersAdded({1, 2, 3, 4});
listener->expectLayersDestroyed({});
- lifecycleManager.applyTransactions({makeRelative(4, 1)});
+ lifecycleManager.applyTransactions(relativeLayerTransaction(4, 1));
EXPECT_TRUE(getRequestedLayerState(lifecycleManager, 4)->isRelativeOf);
- lifecycleManager.applyTransactions({setLayer(4, 1)});
+ lifecycleManager.applyTransactions(setZTransaction(4, 1));
EXPECT_FALSE(getRequestedLayerState(lifecycleManager, 4)->isRelativeOf);
lifecycleManager.commitChanges();
@@ -374,8 +310,7 @@
transactions.back().states.push_back({});
transactions.back().states.front().state.bgColor.a = 0.5;
transactions.back().states.front().state.what = layer_state_t::eBackgroundColorChanged;
- sp<LayerHandle> handle = sp<LayerHandle>::make(1u);
- transactions.back().states.front().state.surface = handle;
+ transactions.back().states.front().layerId = 1;
lifecycleManager.applyTransactions(transactions);
auto& managedLayers = lifecycleManager.getLayers();
@@ -403,13 +338,12 @@
transactions.back().states.push_back({});
transactions.back().states.front().state.bgColor.a = 0.5;
transactions.back().states.front().state.what = layer_state_t::eBackgroundColorChanged;
- sp<LayerHandle> handle = sp<LayerHandle>::make(1u);
- transactions.back().states.front().state.surface = handle;
+ transactions.back().states.front().layerId = 1;
transactions.emplace_back();
transactions.back().states.push_back({});
transactions.back().states.front().state.bgColor.a = 0;
transactions.back().states.front().state.what = layer_state_t::eBackgroundColorChanged;
- transactions.back().states.front().state.surface = handle;
+ transactions.back().states.front().layerId = 1;
lifecycleManager.applyTransactions(transactions);
@@ -437,8 +371,7 @@
transactions.back().states.push_back({});
transactions.back().states.front().state.bgColor.a = 0.5;
transactions.back().states.front().state.what = layer_state_t::eBackgroundColorChanged;
- sp<LayerHandle> handle = sp<LayerHandle>::make(1u);
- transactions.back().states.front().state.surface = handle;
+ transactions.back().states.front().layerId = 1;
transactions.emplace_back();
lifecycleManager.applyTransactions(transactions);
lifecycleManager.onHandlesDestroyed({1});
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index db0b907..b8c4781 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -17,11 +17,9 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-#include "FrontEnd/LayerHandle.h"
#include "FrontEnd/LayerHierarchy.h"
#include "FrontEnd/LayerLifecycleManager.h"
#include "FrontEnd/LayerSnapshotBuilder.h"
-#include "Layer.h"
#include "LayerHierarchyTest.h"
#define UPDATE_AND_VERIFY(BUILDER, ...) \
@@ -268,7 +266,7 @@
transactions.back().states.front().state.what = layer_state_t::eMetadataChanged;
transactions.back().states.front().state.metadata = LayerMetadata();
transactions.back().states.front().state.metadata.setInt32(METADATA_GAME_MODE, 42);
- transactions.back().states.front().state.surface = mHandles[1];
+ transactions.back().states.front().layerId = 1;
transactions.back().states.front().state.layerId = static_cast<int32_t>(1);
mLifecycleManager.applyTransactions(transactions);
UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
@@ -297,8 +295,7 @@
ANATIVEWINDOW_FRAME_RATE_EXACT;
transactions.back().states.front().state.changeFrameRateStrategy =
ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS;
- transactions.back().states.front().state.surface = mHandles[11];
- transactions.back().states.front().state.layerId = static_cast<int32_t>(11);
+ transactions.back().states.front().layerId = 11;
mLifecycleManager.applyTransactions(transactions);
UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
index f4d052d..63ed87b 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
@@ -1455,6 +1455,24 @@
lr.name = "ExplicitExactOrMultiple 29.97 Hz";
EXPECT_EQ(kModeId60Frac, selector.getBestFrameRateMode(layers)->getId());
}
+
+ // Test that 29.97 will choose 30 if 59.94 is not supported
+ {
+ auto selector = createSelector(makeModes(kMode30, kMode60), kModeId60);
+
+ lr.desiredRefreshRate = 29.97_Hz;
+ lr.name = "ExplicitExactOrMultiple 29.97 Hz";
+ EXPECT_EQ(kModeId30, selector.getBestFrameRateMode(layers)->getId());
+ }
+
+ // Test that 59.94 will choose 60 if 59.94 is not supported
+ {
+ auto selector = createSelector(makeModes(kMode60, kMode30Frac, kMode30), kModeId60);
+
+ lr.desiredRefreshRate = 59.94_Hz;
+ lr.name = "ExplicitExactOrMultiple 59.94 Hz";
+ EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers)->getId());
+ }
}
TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_ExplicitExact_WithFractionalRefreshRates) {
@@ -2981,6 +2999,12 @@
layers[0].name = "Test layer";
layers[0].vote = LayerVoteType::Min;
EXPECT_FRAME_RATE_MODE(kMode60, 60_Hz, selector.getBestScoredFrameRate(layers).frameRateMode);
+
+ constexpr FpsRanges kCappedAt60 = {{30_Hz, 90_Hz}, {30_Hz, 60_Hz}};
+ EXPECT_EQ(SetPolicyResult::Changed,
+ selector.setDisplayManagerPolicy(
+ {DisplayModeId(kModeId60), kCappedAt60, kCappedAt60}));
+ EXPECT_FRAME_RATE_MODE(kMode60, 60_Hz, selector.getBestScoredFrameRate(layers).frameRateMode);
}
TEST_P(RefreshRateSelectorTest, frameRateIsCappedByPolicy) {
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
index fd1fd47..e176546 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
@@ -119,7 +119,7 @@
ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60);
- mFlinger.onActiveDisplayChanged(*mDisplay);
+ mFlinger.onActiveDisplayChanged(nullptr, *mDisplay);
mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
mock::createDisplayModeSpecs(kModeId90.value(), false, 0,
@@ -159,7 +159,7 @@
ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
- mFlinger.onActiveDisplayChanged(*mDisplay);
+ mFlinger.onActiveDisplayChanged(nullptr, *mDisplay);
mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
mock::createDisplayModeSpecs(kModeId90.value(), true, 0,
@@ -195,7 +195,7 @@
ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60);
- mFlinger.onActiveDisplayChanged(*mDisplay);
+ mFlinger.onActiveDisplayChanged(nullptr, *mDisplay);
mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
mock::createDisplayModeSpecs(kModeId90.value(), false, 0,
@@ -238,7 +238,7 @@
ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60);
- mFlinger.onActiveDisplayChanged(*mDisplay);
+ mFlinger.onActiveDisplayChanged(nullptr, *mDisplay);
mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
mock::createDisplayModeSpecs(kModeId90_4K.value(), false, 0,
@@ -284,9 +284,43 @@
ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId90_4K);
}
-TEST_F(DisplayModeSwitchingTest, multiDisplay) {
+MATCHER_P2(ModeSwitchingTo, flinger, modeId, "") {
+ if (!arg->getDesiredActiveMode()) {
+ *result_listener << "No desired active mode";
+ return false;
+ }
+
+ if (arg->getDesiredActiveMode()->modeOpt->modePtr->getId() != modeId) {
+ *result_listener << "Unexpected desired active mode " << modeId;
+ return false;
+ }
+
+ if (!flinger->scheduler()->vsyncModulator().isVsyncConfigEarly()) {
+ *result_listener << "VsyncModulator did not shift to early phase";
+ return false;
+ }
+
+ return true;
+}
+
+MATCHER_P(ModeSettledTo, modeId, "") {
+ if (const auto desiredOpt = arg->getDesiredActiveMode()) {
+ *result_listener << "Unsettled desired active mode "
+ << desiredOpt->modeOpt->modePtr->getId();
+ return false;
+ }
+
ftl::FakeGuard guard(kMainThreadContext);
+ if (arg->getActiveMode().modePtr->getId() != modeId) {
+ *result_listener << "Settled to unexpected active mode " << modeId;
+ return false;
+ }
+
+ return true;
+}
+
+TEST_F(DisplayModeSwitchingTest, multiDisplay) {
constexpr HWDisplayId kInnerDisplayHwcId = PrimaryDisplayVariant::HWC_DISPLAY_ID;
constexpr HWDisplayId kOuterDisplayHwcId = kInnerDisplayHwcId + 1;
@@ -309,13 +343,13 @@
const auto& innerDisplay = mDisplay;
- EXPECT_FALSE(innerDisplay->getDesiredActiveMode());
- EXPECT_FALSE(outerDisplay->getDesiredActiveMode());
+ EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId60));
+ EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120));
- EXPECT_EQ(innerDisplay->getActiveMode().modePtr->getId(), kModeId60);
- EXPECT_EQ(outerDisplay->getActiveMode().modePtr->getId(), kModeId120);
+ mFlinger.onActiveDisplayChanged(nullptr, *innerDisplay);
- mFlinger.onActiveDisplayChanged(*innerDisplay);
+ EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId60));
+ EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120));
EXPECT_EQ(NO_ERROR,
mFlinger.setDesiredDisplayModeSpecs(innerDisplay->getDisplayToken().promote(),
@@ -327,12 +361,8 @@
mock::createDisplayModeSpecs(kModeId60.value(),
false, 0.f, 120.f)));
- // Transition on the inner display.
- ASSERT_TRUE(innerDisplay->getDesiredActiveMode());
- EXPECT_EQ(innerDisplay->getDesiredActiveMode()->modeOpt->modePtr->getId(), kModeId90);
-
- // No transition on the outer display.
- EXPECT_FALSE(outerDisplay->getDesiredActiveMode());
+ EXPECT_THAT(innerDisplay, ModeSwitchingTo(&mFlinger, kModeId90));
+ EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120));
const VsyncPeriodChangeTimeline timeline{.refreshRequired = true};
EXPECT_CALL(*mComposer,
@@ -342,31 +372,18 @@
mFlinger.commit();
- // Transition on the inner display.
- ASSERT_TRUE(innerDisplay->getDesiredActiveMode());
- EXPECT_EQ(innerDisplay->getDesiredActiveMode()->modeOpt->modePtr->getId(), kModeId90);
-
- // No transition on the outer display.
- EXPECT_FALSE(outerDisplay->getDesiredActiveMode());
+ EXPECT_THAT(innerDisplay, ModeSwitchingTo(&mFlinger, kModeId90));
+ EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120));
mFlinger.commit();
- // Transition on the inner display.
- EXPECT_FALSE(innerDisplay->getDesiredActiveMode());
- EXPECT_EQ(innerDisplay->getActiveMode().modePtr->getId(), kModeId90);
+ EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId90));
+ EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120));
- // No transition on the outer display.
- EXPECT_FALSE(outerDisplay->getDesiredActiveMode());
- EXPECT_EQ(outerDisplay->getActiveMode().modePtr->getId(), kModeId120);
+ mFlinger.onActiveDisplayChanged(innerDisplay.get(), *outerDisplay);
- mFlinger.onActiveDisplayChanged(*outerDisplay);
-
- // No transition on the inner display.
- EXPECT_FALSE(innerDisplay->getDesiredActiveMode());
-
- // Transition on the outer display.
- ASSERT_TRUE(outerDisplay->getDesiredActiveMode());
- EXPECT_EQ(outerDisplay->getDesiredActiveMode()->modeOpt->modePtr->getId(), kModeId60);
+ EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId90));
+ EXPECT_THAT(outerDisplay, ModeSwitchingTo(&mFlinger, kModeId60));
EXPECT_CALL(*mComposer,
setActiveConfigWithConstraints(kOuterDisplayHwcId,
@@ -375,22 +392,13 @@
mFlinger.commit();
- // No transition on the inner display.
- EXPECT_FALSE(innerDisplay->getDesiredActiveMode());
-
- // Transition on the outer display.
- ASSERT_TRUE(outerDisplay->getDesiredActiveMode());
- EXPECT_EQ(outerDisplay->getDesiredActiveMode()->modeOpt->modePtr->getId(), kModeId60);
+ EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId90));
+ EXPECT_THAT(outerDisplay, ModeSwitchingTo(&mFlinger, kModeId60));
mFlinger.commit();
- // No transition on the inner display.
- EXPECT_FALSE(innerDisplay->getDesiredActiveMode());
- EXPECT_EQ(innerDisplay->getActiveMode().modePtr->getId(), kModeId90);
-
- // Transition on the outer display.
- EXPECT_FALSE(outerDisplay->getDesiredActiveMode());
- EXPECT_EQ(outerDisplay->getActiveMode().modePtr->getId(), kModeId60);
+ EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId90));
+ EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId60));
}
} // namespace
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_InitializeDisplaysTest.cpp
similarity index 93%
rename from services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
rename to services/surfaceflinger/tests/unittests/SurfaceFlinger_InitializeDisplaysTest.cpp
index 98644aa..fc5f2b0 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_InitializeDisplaysTest.cpp
@@ -22,9 +22,9 @@
namespace android {
namespace {
-class OnInitializeDisplaysTest : public DisplayTransactionTest {};
+class InitializeDisplaysTest : public DisplayTransactionTest {};
-TEST_F(OnInitializeDisplaysTest, onInitializeDisplaysSetsUpPrimaryDisplay) {
+TEST_F(InitializeDisplaysTest, commitsPrimaryDisplay) {
using Case = SimplePrimaryDisplayCase;
// --------------------------------------------------------------------
@@ -52,7 +52,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.onInitializeDisplays();
+ FTL_FAKE_GUARD(kMainThreadContext, mFlinger.initializeDisplays());
// --------------------------------------------------------------------
// Postconditions
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index d4b4434..f1a5fc4 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -102,7 +102,6 @@
}
auto& mutableAppConnectionHandle() { return mAppConnectionHandle; }
- auto& mutableVsyncModulator() { return *mVsyncModulator; }
auto& mutableLayerHistory() { return mLayerHistory; }
size_t layerHistorySize() NO_THREAD_SAFETY_ANALYSIS {
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 6334ec8..fc9e653 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -419,10 +419,7 @@
return mFlinger->setDisplayStateLocked(s);
}
- // Allow reading display state without locking, as if called on the SF main thread.
- auto onInitializeDisplays() NO_THREAD_SAFETY_ANALYSIS {
- return mFlinger->onInitializeDisplays();
- }
+ void initializeDisplays() FTL_FAKE_GUARD(kMainThreadContext) { mFlinger->initializeDisplays(); }
auto notifyPowerBoost(int32_t boostId) { return mFlinger->notifyPowerBoost(boostId); }
@@ -505,10 +502,11 @@
return mFlinger->setDesiredDisplayModeSpecs(displayToken, specs);
}
- void onActiveDisplayChanged(const DisplayDevice& activeDisplay) {
+ void onActiveDisplayChanged(const DisplayDevice* inactiveDisplayPtr,
+ const DisplayDevice& activeDisplay) {
Mutex::Autolock lock(mFlinger->mStateLock);
ftl::FakeGuard guard(kMainThreadContext);
- mFlinger->onActiveDisplayChangedLocked(nullptr, activeDisplay);
+ mFlinger->onActiveDisplayChangedLocked(inactiveDisplayPtr, activeDisplay);
}
auto createLayer(LayerCreationArgs& args, const sp<IBinder>& parentHandle,
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index c78148f..d4e2357 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -199,7 +199,7 @@
void modulateVsync() {
static_cast<void>(
- mFlinger.mutableScheduler().mutableVsyncModulator().onRefreshRateChangeInitiated());
+ mFlinger.mutableScheduler().vsyncModulator().onRefreshRateChangeInitiated());
}
bool mHasListenerCallbacks = false;
diff --git a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
index b6427c0..3dea189 100644
--- a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
@@ -19,6 +19,7 @@
#include <limits> // std::numeric_limits
#include <gui/SurfaceComposerClient.h>
+#include "LayerProtoHelper.h"
#include "Tracing/TransactionProtoParser.h"
@@ -27,7 +28,6 @@
namespace android {
TEST(TransactionProtoParserTest, parse) {
- const sp<IBinder> layerHandle = sp<BBinder>::make();
const sp<IBinder> displayHandle = sp<BBinder>::make();
TransactionState t1;
t1.originPid = 1;
@@ -37,7 +37,6 @@
t1.postTime = 5;
layer_state_t layer;
- layer.layerId = 6;
layer.what = std::numeric_limits<uint64_t>::max();
layer.what &= ~static_cast<uint64_t>(layer_state_t::eBufferChanged);
layer.x = 7;
@@ -48,10 +47,9 @@
for (uint32_t i = 0; i < layerCount; i++) {
ResolvedComposerState s;
if (i == 1) {
- layer.parentSurfaceControlForChild =
- sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(), layerHandle, 42,
- "#42");
+ s.parentId = 42;
}
+ s.layerId = 6 + i;
s.state = layer;
t1.states.emplace_back(s);
}
@@ -72,18 +70,10 @@
class TestMapper : public TransactionProtoParser::FlingerDataMapper {
public:
- sp<IBinder> layerHandle;
sp<IBinder> displayHandle;
- TestMapper(sp<IBinder> layerHandle, sp<IBinder> displayHandle)
- : layerHandle(layerHandle), displayHandle(displayHandle) {}
+ TestMapper(sp<IBinder> displayHandle) : displayHandle(displayHandle) {}
- sp<IBinder> getLayerHandle(int32_t id) const override {
- return (id == 42) ? layerHandle : nullptr;
- }
- int64_t getLayerId(const sp<IBinder>& handle) const override {
- return (handle == layerHandle) ? 42 : -1;
- }
sp<IBinder> getDisplayHandle(int32_t id) const {
return (id == 43) ? displayHandle : nullptr;
}
@@ -92,7 +82,7 @@
}
};
- TransactionProtoParser parser(std::make_unique<TestMapper>(layerHandle, displayHandle));
+ TransactionProtoParser parser(std::make_unique<TestMapper>(displayHandle));
proto::TransactionState proto = parser.toProto(t1);
TransactionState t2 = parser.fromProto(proto);
@@ -105,8 +95,8 @@
ASSERT_EQ(t1.states.size(), t2.states.size());
ASSERT_EQ(t1.states[0].state.x, t2.states[0].state.x);
ASSERT_EQ(t1.states[0].state.matrix.dsdx, t2.states[0].state.matrix.dsdx);
- ASSERT_EQ(t1.states[1].state.parentSurfaceControlForChild->getHandle(),
- t2.states[1].state.parentSurfaceControlForChild->getHandle());
+ ASSERT_EQ(t1.states[1].layerId, t2.states[1].layerId);
+ ASSERT_EQ(t1.states[1].parentId, t2.states[1].parentId);
ASSERT_EQ(t1.displays.size(), t2.displays.size());
ASSERT_EQ(t1.displays[1].width, t2.displays[1].width);
diff --git a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
index 482c3a8..74541ac 100644
--- a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
@@ -18,7 +18,11 @@
#include <gtest/gtest.h>
#include <gui/SurfaceComposerClient.h>
+#include <cstdint>
+#include "Client.h"
+#include "FrontEnd/LayerCreationArgs.h"
+#include "FrontEnd/Update.h"
#include "Tracing/RingBuffer.h"
#include "Tracing/TransactionTracing.h"
@@ -42,14 +46,15 @@
}
void queueAndCommitTransaction(int64_t vsyncId) {
+ frontend::Update update;
TransactionState transaction;
transaction.id = static_cast<uint64_t>(vsyncId * 3);
transaction.originUid = 1;
transaction.originPid = 2;
mTracing.addQueuedTransaction(transaction);
std::vector<TransactionState> transactions;
- transactions.emplace_back(transaction);
- mTracing.addCommittedTransactions(transactions, vsyncId);
+ update.transactions.emplace_back(transaction);
+ mTracing.addCommittedTransactions(vsyncId, 0, update, {}, false);
flush(vsyncId);
}
@@ -57,13 +62,25 @@
const std::vector<TransactionState>& expectedTransactions,
int64_t expectedVsyncId) {
EXPECT_EQ(actualProto.vsync_id(), expectedVsyncId);
- EXPECT_EQ(actualProto.transactions().size(),
+ ASSERT_EQ(actualProto.transactions().size(),
static_cast<int32_t>(expectedTransactions.size()));
for (uint32_t i = 0; i < expectedTransactions.size(); i++) {
EXPECT_EQ(actualProto.transactions(static_cast<int32_t>(i)).pid(),
expectedTransactions[i].originPid);
}
}
+
+ LayerCreationArgs getLayerCreationArgs(uint32_t layerId, uint32_t parentId,
+ uint32_t layerIdToMirror, uint32_t flags,
+ bool addToRoot) {
+ LayerCreationArgs args;
+ args.sequence = layerId;
+ args.parentId = parentId;
+ args.layerIdToMirror = layerIdToMirror;
+ args.flags = flags;
+ args.addToRoot = addToRoot;
+ return args;
+ }
};
TEST_F(TransactionTracingTest, addTransactions) {
@@ -79,57 +96,59 @@
// Split incoming transactions into two and commit them in reverse order to test out of order
// commits.
- std::vector<TransactionState> firstTransactionSet =
- std::vector<TransactionState>(transactions.begin() + 50, transactions.end());
int64_t firstTransactionSetVsyncId = 42;
- mTracing.addCommittedTransactions(firstTransactionSet, firstTransactionSetVsyncId);
+ frontend::Update firstUpdate;
+ firstUpdate.transactions =
+ std::vector<TransactionState>(transactions.begin() + 50, transactions.end());
+ mTracing.addCommittedTransactions(firstTransactionSetVsyncId, 0, firstUpdate, {}, false);
int64_t secondTransactionSetVsyncId = 43;
- std::vector<TransactionState> secondTransactionSet =
+ frontend::Update secondUpdate;
+ secondUpdate.transactions =
std::vector<TransactionState>(transactions.begin(), transactions.begin() + 50);
- mTracing.addCommittedTransactions(secondTransactionSet, secondTransactionSetVsyncId);
+ mTracing.addCommittedTransactions(secondTransactionSetVsyncId, 0, secondUpdate, {}, false);
flush(secondTransactionSetVsyncId);
proto::TransactionTraceFile proto = writeToProto();
- EXPECT_EQ(proto.entry().size(), 2);
- verifyEntry(proto.entry(0), firstTransactionSet, firstTransactionSetVsyncId);
- verifyEntry(proto.entry(1), secondTransactionSet, secondTransactionSetVsyncId);
+ ASSERT_EQ(proto.entry().size(), 2);
+ verifyEntry(proto.entry(0), firstUpdate.transactions, firstTransactionSetVsyncId);
+ verifyEntry(proto.entry(1), secondUpdate.transactions, secondTransactionSetVsyncId);
}
class TransactionTracingLayerHandlingTest : public TransactionTracingTest {
protected:
void SetUp() override {
- // add layers
mTracing.setBufferSize(SMALL_BUFFER_SIZE);
- const sp<IBinder> fakeLayerHandle = sp<BBinder>::make();
- mTracing.onLayerAdded(fakeLayerHandle->localBinder(), mParentLayerId, "parent",
- 123 /* flags */, -1 /* parentId */);
- const sp<IBinder> fakeChildLayerHandle = sp<BBinder>::make();
- mTracing.onLayerAdded(fakeChildLayerHandle->localBinder(), mChildLayerId, "child",
- 456 /* flags */, mParentLayerId);
- // add some layer transaction
+ // add layers and add some layer transaction
{
+ frontend::Update update;
+ update.layerCreationArgs.emplace_back(std::move(
+ getLayerCreationArgs(mParentLayerId, /*parentId=*/UNASSIGNED_LAYER_ID,
+ /*layerIdToMirror=*/UNASSIGNED_LAYER_ID, /*flags=*/123,
+ /*addToRoot=*/true)));
+ update.layerCreationArgs.emplace_back(std::move(
+ getLayerCreationArgs(mChildLayerId, mParentLayerId,
+ /*layerIdToMirror=*/UNASSIGNED_LAYER_ID, /*flags=*/456,
+ /*addToRoot=*/true)));
TransactionState transaction;
transaction.id = 50;
ResolvedComposerState layerState;
- layerState.state.surface = fakeLayerHandle;
+ layerState.layerId = mParentLayerId;
layerState.state.what = layer_state_t::eLayerChanged;
layerState.state.z = 42;
transaction.states.emplace_back(layerState);
ResolvedComposerState childState;
- childState.state.surface = fakeChildLayerHandle;
+ childState.layerId = mChildLayerId;
childState.state.what = layer_state_t::eLayerChanged;
childState.state.z = 43;
transaction.states.emplace_back(childState);
mTracing.addQueuedTransaction(transaction);
- std::vector<TransactionState> transactions;
- transactions.emplace_back(transaction);
+ update.transactions.emplace_back(transaction);
VSYNC_ID_FIRST_LAYER_CHANGE = ++mVsyncId;
- mTracing.onLayerAddedToDrawingState(mParentLayerId, VSYNC_ID_FIRST_LAYER_CHANGE);
- mTracing.onLayerAddedToDrawingState(mChildLayerId, VSYNC_ID_FIRST_LAYER_CHANGE);
- mTracing.addCommittedTransactions(transactions, VSYNC_ID_FIRST_LAYER_CHANGE);
+ mTracing.addCommittedTransactions(VSYNC_ID_FIRST_LAYER_CHANGE, 0, update, {}, false);
+
flush(VSYNC_ID_FIRST_LAYER_CHANGE);
}
@@ -139,17 +158,17 @@
TransactionState transaction;
transaction.id = 51;
ResolvedComposerState layerState;
- layerState.state.surface = fakeLayerHandle;
+ layerState.layerId = mParentLayerId;
layerState.state.what = layer_state_t::eLayerChanged | layer_state_t::ePositionChanged;
layerState.state.z = 41;
layerState.state.x = 22;
transaction.states.emplace_back(layerState);
mTracing.addQueuedTransaction(transaction);
- std::vector<TransactionState> transactions;
- transactions.emplace_back(transaction);
+ frontend::Update update;
+ update.transactions.emplace_back(transaction);
VSYNC_ID_SECOND_LAYER_CHANGE = ++mVsyncId;
- mTracing.addCommittedTransactions(transactions, VSYNC_ID_SECOND_LAYER_CHANGE);
+ mTracing.addCommittedTransactions(VSYNC_ID_SECOND_LAYER_CHANGE, 0, update, {}, false);
flush(VSYNC_ID_SECOND_LAYER_CHANGE);
}
@@ -163,8 +182,8 @@
queueAndCommitTransaction(++mVsyncId);
}
- int mParentLayerId = 1;
- int mChildLayerId = 2;
+ uint32_t mParentLayerId = 1;
+ uint32_t mChildLayerId = 2;
int64_t mVsyncId = 0;
int64_t VSYNC_ID_FIRST_LAYER_CHANGE;
int64_t VSYNC_ID_SECOND_LAYER_CHANGE;
@@ -232,42 +251,42 @@
class TransactionTracingMirrorLayerTest : public TransactionTracingTest {
protected:
void SetUp() override {
- // add layers
mTracing.setBufferSize(SMALL_BUFFER_SIZE);
- const sp<IBinder> fakeLayerHandle = sp<BBinder>::make();
- mTracing.onLayerAdded(fakeLayerHandle->localBinder(), mLayerId, "Test Layer",
- 123 /* flags */, -1 /* parentId */);
- const sp<IBinder> fakeMirrorLayerHandle = sp<BBinder>::make();
- mTracing.onMirrorLayerAdded(fakeMirrorLayerHandle->localBinder(), mMirrorLayerId, "Mirror",
- mLayerId);
- mTracing.onLayerAddedToDrawingState(mLayerId, mVsyncId);
- mTracing.onLayerAddedToDrawingState(mMirrorLayerId, mVsyncId);
- // add some layer transaction
+ // add layers and some layer transaction
{
+ frontend::Update update;
+ update.layerCreationArgs.emplace_back(
+ getLayerCreationArgs(mLayerId, /*parentId=*/UNASSIGNED_LAYER_ID,
+ /*layerIdToMirror=*/UNASSIGNED_LAYER_ID, /*flags=*/123,
+ /*addToRoot=*/true));
+ update.layerCreationArgs.emplace_back(
+ getLayerCreationArgs(mMirrorLayerId, UNASSIGNED_LAYER_ID,
+ /*layerIdToMirror=*/mLayerId, /*flags=*/0,
+ /*addToRoot=*/false));
+
TransactionState transaction;
transaction.id = 50;
ResolvedComposerState layerState;
- layerState.state.surface = fakeLayerHandle;
+ layerState.layerId = mLayerId;
layerState.state.what = layer_state_t::eLayerChanged;
layerState.state.z = 42;
transaction.states.emplace_back(layerState);
ResolvedComposerState mirrorState;
- mirrorState.state.surface = fakeMirrorLayerHandle;
+ mirrorState.layerId = mMirrorLayerId;
mirrorState.state.what = layer_state_t::eLayerChanged;
mirrorState.state.z = 43;
transaction.states.emplace_back(mirrorState);
mTracing.addQueuedTransaction(transaction);
- std::vector<TransactionState> transactions;
- transactions.emplace_back(transaction);
- mTracing.addCommittedTransactions(transactions, mVsyncId);
+ update.transactions.emplace_back(transaction);
+ mTracing.addCommittedTransactions(mVsyncId, 0, update, {}, false);
flush(mVsyncId);
}
}
- int mLayerId = 5;
- int mMirrorLayerId = 55;
+ uint32_t mLayerId = 5;
+ uint32_t mMirrorLayerId = 55;
int64_t mVsyncId = 0;
int64_t VSYNC_ID_FIRST_LAYER_CHANGE;
int64_t VSYNC_ID_SECOND_LAYER_CHANGE;