Merge "Add Android version check to GpuWorkTracepointTest" into udc-dev
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index c71c4a0..2ce3fb0 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -7,6 +7,7 @@
rustfmt = --config-path=rustfmt.toml
# Only turn on clang-format check for the following subfolders.
clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
+ cmds/dumpstate/
cmds/idlcli/
cmds/installd/
cmds/servicemanager/
@@ -14,6 +15,7 @@
include/powermanager/
libs/binder/fuzzer/
libs/binder/
+ libs/binderdebug/
libs/binderthreadstate/
libs/graphicsenv/
libs/gui/
@@ -40,3 +42,4 @@
dumpsys_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "^cmds/dumpsys/"
# bugreports matches both cmds/bugreport and cmds/bugreportz
bugreports_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "^cmds/bugreport"
+binder_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "^libs/binder/"
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 788ff03..9701e68 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 &&
@@ -1272,6 +1273,9 @@
dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
bool dump_complete = (status == OK);
dumpsys.stopDumpThread(dump_complete);
+ } else {
+ MYLOGE("Failed to start dump thread for service: %s, status: %d",
+ String8(service).c_str(), status);
}
}
@@ -2065,6 +2069,8 @@
SEC_TO_MSEC(10));
RunDumpsys("DUMPSYS", {"telephony.registry"}, CommandOptions::WithTimeout(90).Build(),
SEC_TO_MSEC(10));
+ RunDumpsys("DUMPSYS", {"isub"}, CommandOptions::WithTimeout(90).Build(),
+ SEC_TO_MSEC(10));
RunDumpsys("DUMPSYS", {"telecom"}, CommandOptions::WithTimeout(90).Build(),
SEC_TO_MSEC(10));
if (include_sensitive_info) {
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 bdd5172..754e7b2 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -77,6 +77,12 @@
}
prebuilt_etc {
+ name: "android.hardware.context_hub.prebuilt.xml",
+ src: "android.hardware.context_hub.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
name: "android.hardware.ethernet.prebuilt.xml",
src: "android.hardware.ethernet.xml",
defaults: ["frameworks_native_data_etc_defaults"],
@@ -107,30 +113,102 @@
}
prebuilt_etc {
+ name: "android.hardware.sensor.accelerometer_limited_axes_uncalibrated.prebuilt.xml",
+ src: "android.hardware.sensor.accelerometer_limited_axes_uncalibrated.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.sensor.accelerometer_limited_axes.prebuilt.xml",
+ src: "android.hardware.sensor.accelerometer_limited_axes.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.sensor.accelerometer.prebuilt.xml",
+ src: "android.hardware.sensor.accelerometer.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
name: "android.hardware.sensor.ambient_temperature.prebuilt.xml",
src: "android.hardware.sensor.ambient_temperature.xml",
defaults: ["frameworks_native_data_etc_defaults"],
}
prebuilt_etc {
+ name: "android.hardware.sensor.assist.prebuilt.xml",
+ src: "android.hardware.sensor.assist.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
name: "android.hardware.sensor.barometer.prebuilt.xml",
src: "android.hardware.sensor.barometer.xml",
defaults: ["frameworks_native_data_etc_defaults"],
}
prebuilt_etc {
+ name: "android.hardware.sensor.compass.prebuilt.xml",
+ src: "android.hardware.sensor.compass.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
name: "android.hardware.sensor.dynamic.head_tracker.prebuilt.xml",
src: "android.hardware.sensor.dynamic.head_tracker.xml",
defaults: ["frameworks_native_data_etc_defaults"],
}
prebuilt_etc {
+ name: "android.hardware.sensor.gyroscope_limited_axes_uncalibrated.prebuilt.xml",
+ src: "android.hardware.sensor.gyroscope_limited_axes_uncalibrated.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.sensor.gyroscope_limited_axes.prebuilt.xml",
+ src: "android.hardware.sensor.gyroscope_limited_axes.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
name: "android.hardware.sensor.gyroscope.prebuilt.xml",
src: "android.hardware.sensor.gyroscope.xml",
defaults: ["frameworks_native_data_etc_defaults"],
}
prebuilt_etc {
+ name: "android.hardware.sensor.heading.prebuilt.xml",
+ src: "android.hardware.sensor.heading.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.sensor.heartrate.ecg.prebuilt.xml",
+ src: "android.hardware.sensor.heartrate.ecg.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.sensor.heartrate.fitness.prebuilt.xml",
+ src: "android.hardware.sensor.heartrate.fitness.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.sensor.heartrate.prebuilt.xml",
+ src: "android.hardware.sensor.heartrate.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.sensor.hifi_sensors.prebuilt.xml",
+ src: "android.hardware.sensor.hifi_sensors.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
name: "android.hardware.sensor.hinge_angle.prebuilt.xml",
src: "android.hardware.sensor.hinge_angle.xml",
defaults: ["frameworks_native_data_etc_defaults"],
@@ -155,6 +233,18 @@
}
prebuilt_etc {
+ name: "android.hardware.sensor.stepcounter.prebuilt.xml",
+ src: "android.hardware.sensor.stepcounter.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.sensor.stepdetector.prebuilt.xml",
+ src: "android.hardware.sensor.stepdetector.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
name: "android.hardware.telephony.gsm.prebuilt.xml",
src: "android.hardware.telephony.gsm.xml",
defaults: ["frameworks_native_data_etc_defaults"],
@@ -167,6 +257,12 @@
}
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
new file mode 100644
index 0000000..d36c958
--- /dev/null
+++ b/data/etc/android.hardware.telephony.satellite.xml
@@ -0,0 +1,20 @@
+<?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 vendor service APIs. -->
+<permissions>
+ <feature name="android.hardware.telephony.satellite" />
+</permissions>
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index e4926a6..daeebec 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -555,6 +555,8 @@
* range in use.
*
* Must be finite && >= 1.0f
+ *
+ * Available since API level 34.
*/
void ASurfaceTransaction_setExtendedRangeBrightness(ASurfaceTransaction* transaction,
ASurfaceControl* surface_control,
diff --git a/include/input/PropertyMap.h b/include/input/PropertyMap.h
index 28e4816..2e44142 100644
--- a/include/input/PropertyMap.h
+++ b/include/input/PropertyMap.h
@@ -18,7 +18,11 @@
#include <android-base/result.h>
#include <utils/Tokenizer.h>
+
+#include <optional>
+#include <string>
#include <unordered_map>
+#include <unordered_set>
namespace android {
@@ -57,14 +61,18 @@
*/
void addProperty(const std::string& key, const std::string& value);
- /* 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.)
+ /* 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 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;
+ 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..49dd9c7 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*",
],
}
@@ -354,6 +355,7 @@
cc_library_static {
name: "libbinder_rpc_no_kernel",
+ vendor_available: true,
defaults: [
"libbinder_common_defaults",
"libbinder_android_defaults",
@@ -406,6 +408,7 @@
cc_defaults {
name: "libbinder_tls_defaults",
defaults: ["libbinder_tls_shared_deps"],
+ vendor_available: true,
host_supported: true,
header_libs: [
@@ -432,7 +435,7 @@
defaults: ["libbinder_tls_defaults"],
}
-cc_library_shared {
+cc_library {
name: "libbinder_trusty",
vendor: true,
srcs: [
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/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_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index 43159d8..89fd7a3 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -56,12 +56,12 @@
*
* \param binder object to register globally with the service manager.
* \param instance identifier of the service. This will be used to lookup the service.
- * \param flag an AServiceManager_AddServiceFlag enum to denote how the service should be added.
+ * \param flags an AServiceManager_AddServiceFlag enum to denote how the service should be added.
*
* \return EX_NONE on success.
*/
-__attribute__((warn_unused_result)) binder_exception_t AServiceManager_addServiceWithFlag(
- AIBinder* binder, const char* instance, const AServiceManager_AddServiceFlag flag)
+__attribute__((warn_unused_result)) binder_exception_t AServiceManager_addServiceWithFlags(
+ AIBinder* binder, const char* instance, const AServiceManager_AddServiceFlag flags)
__INTRODUCED_IN(34);
/**
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/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 1078fb2..1c5f79f 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -158,7 +158,7 @@
AServiceManager_getUpdatableApexName; # systemapi
AServiceManager_registerForServiceNotifications; # systemapi llndk
AServiceManager_NotificationRegistration_delete; # systemapi llndk
- AServiceManager_addServiceWithFlag; # systemapi llndk
+ AServiceManager_addServiceWithFlags; # systemapi llndk
};
LIBBINDER_NDK_PLATFORM {
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/ndk/service_manager.cpp b/libs/binder/ndk/service_manager.cpp
index 84da459..2977786 100644
--- a/libs/binder/ndk/service_manager.cpp
+++ b/libs/binder/ndk/service_manager.cpp
@@ -42,15 +42,15 @@
return PruneException(exception);
}
-binder_exception_t AServiceManager_addServiceWithFlag(AIBinder* binder, const char* instance,
- const AServiceManager_AddServiceFlag flag) {
+binder_exception_t AServiceManager_addServiceWithFlags(AIBinder* binder, const char* instance,
+ const AServiceManager_AddServiceFlag flags) {
if (binder == nullptr || instance == nullptr) {
return EX_ILLEGAL_ARGUMENT;
}
sp<IServiceManager> sm = defaultServiceManager();
- bool allowIsolated = flag & AServiceManager_AddServiceFlag::ADD_SERVICE_ALLOW_ISOLATED;
+ bool allowIsolated = flags & AServiceManager_AddServiceFlag::ADD_SERVICE_ALLOW_ISOLATED;
status_t exception = sm->addService(String16(instance), binder->getBinder(), allowIsolated);
return PruneException(exception);
}
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 882f1d6..cefc42f 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -51,6 +51,7 @@
constexpr char kLazyBinderNdkUnitTestService[] = "LazyBinderNdkUnitTest";
constexpr char kForcePersistNdkUnitTestService[] = "ForcePersistNdkUnitTestService";
constexpr char kActiveServicesNdkUnitTestService[] = "ActiveServicesNdkUnitTestService";
+constexpr char kBinderNdkUnitTestServiceFlagged[] = "BinderNdkUnitTestFlagged";
constexpr unsigned int kShutdownWaitTime = 11;
constexpr uint64_t kContextTestValue = 0xb4e42fb4d9a1d715;
@@ -158,6 +159,24 @@
return 1; // should not return
}
+int generatedFlaggedService(const AServiceManager_AddServiceFlag flags, const char* instance) {
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+
+ auto service = ndk::SharedRefBase::make<MyBinderNdkUnitTest>();
+ auto binder = service->asBinder();
+
+ binder_exception_t exception =
+ AServiceManager_addServiceWithFlags(binder.get(), instance, flags);
+
+ if (exception != EX_NONE) {
+ LOG(FATAL) << "Could not register: " << exception << " " << instance;
+ }
+
+ ABinderProcess_joinThreadPool();
+
+ return 1; // should not return
+}
+
// manually-written parceling class considered bad practice
class MyFoo : public IFoo {
binder_status_t doubleNumber(int32_t in, int32_t* out) override {
@@ -847,6 +866,12 @@
EXPECT_EQ("CMD", shellCmdToString(testService, {"C", "M", "D"}));
}
+TEST(NdkBinder, FlaggedServiceAccessible) {
+ static const sp<android::IServiceManager> sm(android::defaultServiceManager());
+ sp<IBinder> testService = sm->getService(String16(kBinderNdkUnitTestServiceFlagged));
+ ASSERT_NE(nullptr, testService);
+}
+
TEST(NdkBinder, GetClassInterfaceDescriptor) {
ASSERT_STREQ(IFoo::kIFooDescriptor, AIBinder_Class_getDescriptor(IFoo::kClass));
}
@@ -901,6 +926,13 @@
prctl(PR_SET_PDEATHSIG, SIGHUP);
return generatedService();
}
+ if (fork() == 0) {
+ prctl(PR_SET_PDEATHSIG, SIGHUP);
+ // We may want to change this flag to be more generic ones for the future
+ AServiceManager_AddServiceFlag test_flags =
+ AServiceManager_AddServiceFlag::ADD_SERVICE_ALLOW_ISOLATED;
+ return generatedFlaggedService(test_flags, kBinderNdkUnitTestServiceFlagged);
+ }
ABinderProcess_setThreadPoolMaxThreadCount(1); // to receive death notifications/callbacks
ABinderProcess_startThreadPool();
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/Android.bp b/libs/binder/tests/Android.bp
index 0f0d64a..61a047b 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -138,6 +138,7 @@
aidl_interface {
name: "binderRpcTestIface",
+ vendor_available: true,
host_supported: true,
unstable: true,
srcs: [
@@ -159,6 +160,7 @@
cc_library_static {
name: "libbinder_tls_test_utils",
host_supported: true,
+ vendor_available: true,
target: {
darwin: {
enabled: false,
@@ -441,6 +443,37 @@
}
cc_test {
+ name: "binderRpcToTrustyTest",
+ vendor: true,
+ host_supported: false,
+ defaults: [
+ "binderRpcTest_common_defaults",
+ "binderRpcTest_static_defaults",
+ ],
+
+ srcs: [
+ "binderRpcTest.cpp",
+ "binderRpcTestCommon.cpp",
+ "binderRpcUniversalTests.cpp",
+ ],
+
+ cflags: [
+ "-DBINDER_RPC_TO_TRUSTY_TEST",
+ ],
+
+ static_libs: [
+ // We want to link libbinder statically so we can push the binary
+ // to the device for testing independently of the library
+ "libbinder_rpc_no_kernel",
+ "libbinder_trusty",
+ "libtrusty",
+ ],
+
+ test_suites: ["device-tests"],
+ require_root: true,
+}
+
+cc_test {
name: "RpcTlsUtilsTest",
host_supported: true,
target: {
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 9f54087..8d1def1 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -28,10 +28,10 @@
#include <sys/prctl.h>
#include <sys/socket.h>
-#ifdef __ANDROID_VENDOR__
+#ifdef BINDER_RPC_TO_TRUSTY_TEST
#include <binder/RpcTransportTipcAndroid.h>
#include <trusty/tipc.h>
-#endif // __ANDROID_VENDOR__
+#endif // BINDER_RPC_TO_TRUSTY_TEST
#include "binderRpcTestCommon.h"
#include "binderRpcTestFixture.h"
@@ -50,7 +50,7 @@
constexpr bool kEnableSharedLibs = true;
#endif
-#ifdef __ANDROID_VENDOR__
+#ifdef BINDER_RPC_TO_TRUSTY_TEST
constexpr char kTrustyIpcDevice[] = "/dev/trusty-ipc-dev0";
#endif
@@ -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;
@@ -212,6 +214,7 @@
return serverFd;
}
+#ifndef BINDER_RPC_TO_TRUSTY_TEST
static base::unique_fd connectToUnixBootstrap(const RpcTransportFd& transportFd) {
base::unique_fd sockClient, sockServer;
if (!base::Socketpair(SOCK_STREAM, &sockClient, &sockServer)) {
@@ -230,22 +233,10 @@
}
return std::move(sockClient);
}
+#endif // BINDER_RPC_TO_TRUSTY_TEST
-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 +245,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());
@@ -315,13 +310,13 @@
for (size_t i = 0; i < options.numSessions; i++) {
std::unique_ptr<RpcTransportCtxFactory> factory;
if (socketType == SocketType::TIPC) {
-#ifdef __ANDROID_VENDOR__
+#ifdef BINDER_RPC_TO_TRUSTY_TEST
factory = RpcTransportCtxFactoryTipcAndroid::make();
#else
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 +346,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);
@@ -379,7 +380,7 @@
break;
case SocketType::TIPC:
status = session->setupPreconnectedClient({}, [=]() {
-#ifdef __ANDROID_VENDOR__
+#ifdef BINDER_RPC_TO_TRUSTY_TEST
auto port = trustyIpcPort(serverVersion);
int tipcFd = tipc_connect(kTrustyIpcDevice, port.c_str());
return tipcFd >= 0 ? android::base::unique_fd(tipcFd)
@@ -465,7 +466,9 @@
constexpr size_t kNumThreads = 10;
constexpr size_t kNumCalls = kNumThreads + 3;
auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
- testThreadPoolOverSaturated(proc.rootIface, kNumCalls, 250 /*ms*/);
+
+ // b/272429574 - below 500ms, the test fails
+ testThreadPoolOverSaturated(proc.rootIface, kNumCalls, 500 /*ms*/);
}
TEST_P(BinderRpc, ThreadPoolLimitOutgoing) {
@@ -478,7 +481,9 @@
constexpr size_t kNumCalls = kNumOutgoingConnections + 3;
auto proc = createRpcTestSocketServerProcess(
{.numThreads = kNumThreads, .numOutgoingConnections = kNumOutgoingConnections});
- testThreadPoolOverSaturated(proc.rootIface, kNumCalls, 250 /*ms*/);
+
+ // b/272429574 - below 500ms, the test fails
+ testThreadPoolOverSaturated(proc.rootIface, kNumCalls, 500 /*ms*/);
}
TEST_P(BinderRpc, ThreadingStressTest) {
@@ -651,6 +656,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";
@@ -668,7 +699,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));
@@ -681,6 +712,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;
}
@@ -702,7 +737,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));
@@ -735,8 +770,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));
@@ -755,19 +789,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) {
@@ -1076,6 +1104,15 @@
ASSERT_EQ(beforeFds, countFds()) << (system("ls -l /proc/self/fd/"), "fd leak?");
}
+#ifdef BINDER_RPC_TO_TRUSTY_TEST
+INSTANTIATE_TEST_CASE_P(Trusty, BinderRpc,
+ ::testing::Combine(::testing::Values(SocketType::TIPC),
+ ::testing::Values(RpcSecurity::RAW),
+ ::testing::ValuesIn(testVersions()),
+ ::testing::ValuesIn(testVersions()),
+ ::testing::Values(true), ::testing::Values(true)),
+ BinderRpc::PrintParamInfo);
+#else // BINDER_RPC_TO_TRUSTY_TEST
static bool testSupportVsockLoopback() {
// We don't need to enable TLS to know if vsock is supported.
unsigned int vsockPort = allocateVsockPort();
@@ -1180,21 +1217,6 @@
return ret;
}
-static std::vector<SocketType> testTipcSocketTypes() {
-#ifdef __ANDROID_VENDOR__
- auto port = trustyIpcPort(RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL);
- int tipcFd = tipc_connect(kTrustyIpcDevice, port.c_str());
- if (tipcFd >= 0) {
- close(tipcFd);
- return {SocketType::TIPC};
- }
-#endif // __ANDROID_VENDOR__
-
- // TIPC is not supported on this device, most likely
- // because /dev/trusty-ipc-dev0 is missing
- return {};
-}
-
INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc,
::testing::Combine(::testing::ValuesIn(testSocketTypes()),
::testing::ValuesIn(RpcSecurityValues()),
@@ -1204,14 +1226,6 @@
::testing::Values(false, true)),
BinderRpc::PrintParamInfo);
-INSTANTIATE_TEST_CASE_P(Trusty, BinderRpc,
- ::testing::Combine(::testing::ValuesIn(testTipcSocketTypes()),
- ::testing::Values(RpcSecurity::RAW),
- ::testing::ValuesIn(testVersions()),
- ::testing::ValuesIn(testVersions()),
- ::testing::Values(true), ::testing::Values(true)),
- BinderRpc::PrintParamInfo);
-
class BinderRpcServerRootObject
: public ::testing::TestWithParam<std::tuple<bool, bool, RpcSecurity>> {};
@@ -1222,7 +1236,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);
@@ -1318,7 +1332,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));
}
};
@@ -1326,7 +1340,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)));
@@ -1342,7 +1356,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>();
@@ -1391,7 +1405,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: {
@@ -1470,7 +1484,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();
@@ -1575,7 +1589,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();
}
@@ -1647,7 +1661,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;
@@ -1980,6 +1994,7 @@
testing::Values(RpcKeyFormat::PEM, RpcKeyFormat::DER),
testing::ValuesIn(testVersions())),
RpcTransportTlsKeyTest::PrintParamInfo);
+#endif // BINDER_RPC_TO_TRUSTY_TEST
} // namespace android
diff --git a/libs/binder/tests/binderRpcTestCommon.h b/libs/binder/tests/binderRpcTestCommon.h
index d129661..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) {
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 ca5a117..a9736d5 100644
--- a/libs/binder/tests/binderRpcTestService.cpp
+++ b/libs/binder/tests/binderRpcTestService.cpp
@@ -116,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/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp
index 768fbe1..6da7a5b 100644
--- a/libs/binder/tests/parcel_fuzzer/binder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder.cpp
@@ -367,13 +367,14 @@
FUZZ_LOG() << "about to call readFromParcel() with status for SingleDataParcelable";
parcelables::SingleDataParcelable singleDataParcelable;
status_t status = singleDataParcelable.readFromParcel(&p);
- FUZZ_LOG() <<" status: " << status;
+ FUZZ_LOG() << " status: " << status;
},
[] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
FUZZ_LOG() << "about to call readFromParcel() with status for GenericDataParcelable";
parcelables::GenericDataParcelable genericDataParcelable;
status_t status = genericDataParcelable.readFromParcel(&p);
- FUZZ_LOG() <<" status: " << status;
+ FUZZ_LOG() << " status: " << status;
+ FUZZ_LOG() << " toString() result: " << genericDataParcelable.toString();
},
};
// clang-format on
diff --git a/libs/binder/tests/parcel_fuzzer/parcelables/GenericDataParcelable.aidl b/libs/binder/tests/parcel_fuzzer/parcelables/GenericDataParcelable.aidl
index f1079e9..01e6999 100644
--- a/libs/binder/tests/parcel_fuzzer/parcelables/GenericDataParcelable.aidl
+++ b/libs/binder/tests/parcel_fuzzer/parcelables/GenericDataParcelable.aidl
@@ -22,4 +22,7 @@
IBinder binder;
ParcelFileDescriptor fileDescriptor;
int[] array;
-}
\ No newline at end of file
+ String greatString;
+ @utf8InCpp
+ String greaterString;
+}
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/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 183acc1..cd35d2f 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -91,6 +91,9 @@
compile_multilib: "both",
header_libs: ["libsurfaceflinger_headers"],
+ data: [
+ ":libgui_test",
+ ],
}
cc_test {
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 3344e0b..5f80c16 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -512,6 +512,22 @@
bgSurface->expectTap(1, 1);
}
+TEST_F(InputSurfacesTest, input_respects_surface_insets_with_replaceTouchableRegionWithCrop) {
+ std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
+ bgSurface->showAt(100, 100);
+
+ fgSurface->mInputInfo.surfaceInset = 5;
+ fgSurface->mInputInfo.replaceTouchableRegionWithCrop = true;
+ fgSurface->showAt(100, 100);
+
+ injectTap(106, 106);
+ fgSurface->expectTap(1, 1);
+
+ injectTap(101, 101);
+ bgSurface->expectTap(1, 1);
+}
+
// Ensure a surface whose insets are cropped, handles the touch offset correctly. ref:b/120413463
TEST_F(InputSurfacesTest, input_respects_cropped_surface_insets) {
std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100);
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index f38dd98..869458c 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -167,6 +167,7 @@
cc_defaults {
name: "libinput_fuzz_defaults",
+ cpp_std: "c++20",
host_supported: true,
shared_libs: [
"libutils",
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 ed9ac9f..548f894 100644
--- a/libs/input/PropertyMap.cpp
+++ b/libs/input/PropertyMap.cpp
@@ -16,6 +16,8 @@
#define LOG_TAG "PropertyMap"
+#include <cstdlib>
+
#include <input/PropertyMap.h>
#include <log/log.h>
@@ -44,62 +46,76 @@
mProperties.emplace(key, value);
}
+std::unordered_set<std::string> PropertyMap::getKeysWithPrefix(const std::string& prefix) const {
+ std::unordered_set<std::string> keys;
+ for (const auto& [key, _] : mProperties) {
+ if (key.starts_with(prefix)) {
+ keys.insert(key);
+ }
+ }
+ return keys;
+}
+
bool PropertyMap::hasProperty(const std::string& key) const {
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;
+}
+
+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);
+ if (*end != '\0') {
+ ALOGW("Property key '%s' has invalid value '%s'. Expected a double.", key.c_str(),
+ stringValue->c_str());
+ return std::nullopt;
+ }
+ 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/jpegrecoverymap/include/jpegrecoverymap/jpegr.h b/libs/jpegrecoverymap/include/jpegrecoverymap/jpegr.h
index 9b2dde7..1ab1dd7 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,21 +204,42 @@
* 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 recovery_map destination of the decoded recovery map.
+ * @param compressed_jpegr_image compressed JPEGR image.
+ * @param dest destination of the uncompressed JPEGR image.
+ * @param max_display_boost (optional) the maximum available boost supported by a display
+ * @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,
+ float max_display_boost = -1.0f,
jr_exif_ptr exif = nullptr,
jpegr_output_format output_format = JPEGR_OUTPUT_HDR_LINEAR,
- jr_uncompressed_ptr recovery_map = nullptr);
+ jr_uncompressed_ptr recovery_map = nullptr,
+ jr_metadata_ptr metadata = nullptr);
/*
* Gets Info from JPEGR file without decoding it.
@@ -257,6 +283,7 @@
* @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 max_display_boost the maximum available boost supported by a display
* @param dest reconstructed HDR image
* @return NO_ERROR if calculation succeeds, error code if error occurs.
*/
@@ -264,6 +291,7 @@
jr_uncompressed_ptr uncompressed_recovery_map,
jr_metadata_ptr metadata,
jpegr_output_format output_format,
+ float max_display_boost,
jr_uncompressed_ptr dest);
private:
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/include/jpegrecoverymap/recoverymapmath.h b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymapmath.h
index 8b5318f..67d2a6a 100644
--- a/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymapmath.h
+++ b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymapmath.h
@@ -135,6 +135,16 @@
}
}
+ RecoveryLUT(jr_metadata_ptr metadata, float displayBoost) {
+ float boostFactor = displayBoost > 0 ? displayBoost / metadata->maxContentBoost : 1.0f;
+ for (int idx = 0; idx < kRecoveryFactorNumEntries; idx++) {
+ float value = static_cast<float>(idx) / static_cast<float>(kRecoveryFactorNumEntries - 1);
+ float logBoost = log2(metadata->minContentBoost) * (1.0f - value)
+ + log2(metadata->maxContentBoost) * value;
+ mRecoveryTable[idx] = exp2(logBoost * boostFactor);
+ }
+ }
+
~RecoveryLUT() {
}
@@ -357,6 +367,7 @@
* value, with the given hdr ratio, to the given sdr input in the range [0, 1].
*/
Color applyRecovery(Color e, float recovery, jr_metadata_ptr metadata);
+Color applyRecovery(Color e, float recovery, jr_metadata_ptr metadata, float displayBoost);
Color applyRecoveryLUT(Color e, float recovery, RecoveryLUT& recoveryLUT);
/*
diff --git a/libs/jpegrecoverymap/jpegr.cpp b/libs/jpegrecoverymap/jpegr.cpp
index f8763c6..e395d51 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;
@@ -330,9 +330,11 @@
/* Decode API */
status_t JpegR::decodeJPEGR(jr_compressed_ptr compressed_jpegr_image,
jr_uncompressed_ptr dest,
+ float max_display_boost,
jr_exif_ptr exif,
jpegr_output_format output_format,
- jr_uncompressed_ptr recovery_map) {
+ jr_uncompressed_ptr recovery_map,
+ jr_metadata_ptr metadata) {
if (compressed_jpegr_image == nullptr || dest == nullptr) {
return ERROR_JPEGR_INVALID_NULL_PTR;
}
@@ -387,6 +389,18 @@
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;
}
@@ -417,13 +431,8 @@
uncompressed_yuv_420_image.width = jpeg_decoder.getDecompressedImageWidth();
uncompressed_yuv_420_image.height = jpeg_decoder.getDecompressedImageHeight();
- jpegr_metadata metadata;
- 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,
+ max_display_boost, dest));
return NO_ERROR;
}
@@ -659,6 +668,7 @@
jr_uncompressed_ptr uncompressed_recovery_map,
jr_metadata_ptr metadata,
jpegr_output_format output_format,
+ float max_display_boost,
jr_uncompressed_ptr dest) {
if (uncompressed_yuv_420_image == nullptr
|| uncompressed_recovery_map == nullptr
@@ -670,13 +680,15 @@
dest->width = uncompressed_yuv_420_image->width;
dest->height = uncompressed_yuv_420_image->height;
ShepardsIDW idwTable(kMapDimensionScaleFactor);
- RecoveryLUT recoveryLUT(metadata);
+ float display_boost = max_display_boost > 0 ?
+ std::min(max_display_boost, metadata->maxContentBoost)
+ : metadata->maxContentBoost;
+ RecoveryLUT recoveryLUT(metadata, display_boost);
JobQueue jobQueue;
std::function<void()> applyRecMap = [uncompressed_yuv_420_image, uncompressed_recovery_map,
metadata, dest, &jobQueue, &idwTable, output_format,
- &recoveryLUT]() -> void {
- const float hdr_ratio = metadata->maxContentBoost;
+ &recoveryLUT, display_boost]() -> void {
size_t width = uncompressed_yuv_420_image->width;
size_t height = uncompressed_yuv_420_image->height;
@@ -702,12 +714,13 @@
} else {
recovery = sampleMap(uncompressed_recovery_map, map_scale_factor, x, y, idwTable);
}
+
#if USE_APPLY_RECOVERY_LUT
Color rgb_hdr = applyRecoveryLUT(rgb_sdr, recovery, recoveryLUT);
#else
- Color rgb_hdr = applyRecovery(rgb_sdr, recovery, metadata);
+ Color rgb_hdr = applyRecovery(rgb_sdr, recovery, metadata, display_boost);
#endif
- rgb_hdr = rgb_hdr / metadata->maxContentBoost;
+ rgb_hdr = rgb_hdr / display_boost;
size_t pixel_idx = x + y * width;
switch (output_format) {
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/recoverymapmath.cpp b/libs/jpegrecoverymap/recoverymapmath.cpp
index 20c32ed..2cffde3 100644
--- a/libs/jpegrecoverymap/recoverymapmath.cpp
+++ b/libs/jpegrecoverymap/recoverymapmath.cpp
@@ -463,6 +463,13 @@
return e * recoveryFactor;
}
+Color applyRecovery(Color e, float recovery, jr_metadata_ptr metadata, float displayBoost) {
+ float logBoost = log2(metadata->minContentBoost) * (1.0f - recovery)
+ + log2(metadata->maxContentBoost) * recovery;
+ float recoveryFactor = exp2(logBoost * displayBoost / metadata->maxContentBoost);
+ return e * recoveryFactor;
+}
+
Color applyRecoveryLUT(Color e, float recovery, RecoveryLUT& recoveryLUT) {
float recoveryFactor = recoveryLUT.getRecoveryFactor(recovery);
return e * recoveryFactor;
diff --git a/libs/jpegrecoverymap/tests/jpegr_test.cpp b/libs/jpegrecoverymap/tests/jpegr_test.cpp
index 0a7d20a..df90f53 100644
--- a/libs/jpegrecoverymap/tests/jpegr_test.cpp
+++ b/libs/jpegrecoverymap/tests/jpegr_test.cpp
@@ -152,7 +152,8 @@
timerStart(&applyRecMapTime);
for (auto i = 0; i < kProfileCount; i++) {
- ASSERT_EQ(OK, applyRecoveryMap(yuv420Image, map, metadata, JPEGR_OUTPUT_HDR_HLG, dest));
+ ASSERT_EQ(OK, applyRecoveryMap(yuv420Image, map, metadata, JPEGR_OUTPUT_HDR_HLG,
+ metadata->maxContentBoost /* displayBoost */, dest));
}
timerStop(&applyRecMapTime);
@@ -170,11 +171,11 @@
jpegRCodec.encodeJPEGR(nullptr, nullptr, nullptr, static_cast<jpegr_transfer_function>(0),
nullptr);
jpegRCodec.encodeJPEGR(nullptr, nullptr, static_cast<jpegr_transfer_function>(0), nullptr);
- jpegRCodec.decodeJPEGR(nullptr, nullptr, nullptr);
+ jpegRCodec.decodeJPEGR(nullptr, nullptr);
}
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 +190,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 +477,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..5ef79e9 100644
--- a/libs/jpegrecoverymap/tests/recoverymapmath_test.cpp
+++ b/libs/jpegrecoverymap/tests/recoverymapmath_test.cpp
@@ -554,9 +554,10 @@
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);
+ RecoveryLUT recoveryLUTWithBoost(&metadata, metadata.maxContentBoost);
for (int idx = 0; idx < kRecoveryFactorNumEntries; idx++) {
float value = static_cast<float>(idx) / static_cast<float>(kRecoveryFactorNumEntries - 1);
EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), value, &metadata),
@@ -569,13 +570,24 @@
applyRecoveryLUT(RgbGreen(), value, recoveryLUT));
EXPECT_RGB_NEAR(applyRecovery(RgbBlue(), value, &metadata),
applyRecoveryLUT(RgbBlue(), value, recoveryLUT));
+ EXPECT_RGB_EQ(applyRecoveryLUT(RgbBlack(), value, recoveryLUT),
+ applyRecoveryLUT(RgbBlack(), value, recoveryLUTWithBoost));
+ EXPECT_RGB_EQ(applyRecoveryLUT(RgbWhite(), value, recoveryLUT),
+ applyRecoveryLUT(RgbWhite(), value, recoveryLUTWithBoost));
+ EXPECT_RGB_EQ(applyRecoveryLUT(RgbRed(), value, recoveryLUT),
+ applyRecoveryLUT(RgbRed(), value, recoveryLUTWithBoost));
+ EXPECT_RGB_EQ(applyRecoveryLUT(RgbGreen(), value, recoveryLUT),
+ applyRecoveryLUT(RgbGreen(), value, recoveryLUTWithBoost));
+ EXPECT_RGB_EQ(applyRecoveryLUT(RgbBlue(), value, recoveryLUT),
+ applyRecoveryLUT(RgbBlue(), value, recoveryLUTWithBoost));
}
}
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);
+ RecoveryLUT recoveryLUTWithBoost(&metadata, metadata.maxContentBoost);
for (int idx = 0; idx < kRecoveryFactorNumEntries; idx++) {
float value = static_cast<float>(idx) / static_cast<float>(kRecoveryFactorNumEntries - 1);
EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), value, &metadata),
@@ -588,14 +600,25 @@
applyRecoveryLUT(RgbGreen(), value, recoveryLUT));
EXPECT_RGB_NEAR(applyRecovery(RgbBlue(), value, &metadata),
applyRecoveryLUT(RgbBlue(), value, recoveryLUT));
+ EXPECT_RGB_EQ(applyRecoveryLUT(RgbBlack(), value, recoveryLUT),
+ applyRecoveryLUT(RgbBlack(), value, recoveryLUTWithBoost));
+ EXPECT_RGB_EQ(applyRecoveryLUT(RgbWhite(), value, recoveryLUT),
+ applyRecoveryLUT(RgbWhite(), value, recoveryLUTWithBoost));
+ EXPECT_RGB_EQ(applyRecoveryLUT(RgbRed(), value, recoveryLUT),
+ applyRecoveryLUT(RgbRed(), value, recoveryLUTWithBoost));
+ EXPECT_RGB_EQ(applyRecoveryLUT(RgbGreen(), value, recoveryLUT),
+ applyRecoveryLUT(RgbGreen(), value, recoveryLUTWithBoost));
+ EXPECT_RGB_EQ(applyRecoveryLUT(RgbBlue(), value, recoveryLUT),
+ applyRecoveryLUT(RgbBlue(), value, recoveryLUTWithBoost));
}
}
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);
+ RecoveryLUT recoveryLUTWithBoost(&metadata, metadata.maxContentBoost);
for (int idx = 0; idx < kRecoveryFactorNumEntries; idx++) {
float value = static_cast<float>(idx) / static_cast<float>(kRecoveryFactorNumEntries - 1);
EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), value, &metadata),
@@ -608,6 +631,16 @@
applyRecoveryLUT(RgbGreen(), value, recoveryLUT));
EXPECT_RGB_NEAR(applyRecovery(RgbBlue(), value, &metadata),
applyRecoveryLUT(RgbBlue(), value, recoveryLUT));
+ EXPECT_RGB_EQ(applyRecoveryLUT(RgbBlack(), value, recoveryLUT),
+ applyRecoveryLUT(RgbBlack(), value, recoveryLUTWithBoost));
+ EXPECT_RGB_EQ(applyRecoveryLUT(RgbWhite(), value, recoveryLUT),
+ applyRecoveryLUT(RgbWhite(), value, recoveryLUTWithBoost));
+ EXPECT_RGB_EQ(applyRecoveryLUT(RgbRed(), value, recoveryLUT),
+ applyRecoveryLUT(RgbRed(), value, recoveryLUTWithBoost));
+ EXPECT_RGB_EQ(applyRecoveryLUT(RgbGreen(), value, recoveryLUT),
+ applyRecoveryLUT(RgbGreen(), value, recoveryLUTWithBoost));
+ EXPECT_RGB_EQ(applyRecoveryLUT(RgbBlue(), value, recoveryLUT),
+ applyRecoveryLUT(RgbBlue(), value, recoveryLUTWithBoost));
}
}
}
@@ -659,8 +692,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 +750,9 @@
}
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 };
+ float displayBoost = metadata.maxContentBoost;
EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), 0.0f, &metadata), RgbBlack());
EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), 0.5f, &metadata), RgbBlack());
@@ -774,6 +808,19 @@
EXPECT_RGB_NEAR(applyRecovery(e, 0.5f, &metadata), e);
EXPECT_RGB_NEAR(applyRecovery(e, 0.75f, &metadata), e * 2.0f);
EXPECT_RGB_NEAR(applyRecovery(e, 1.0f, &metadata), e * 4.0f);
+
+ EXPECT_RGB_EQ(applyRecovery(RgbBlack(), 1.0f, &metadata),
+ applyRecovery(RgbBlack(), 1.0f, &metadata, displayBoost));
+ EXPECT_RGB_EQ(applyRecovery(RgbWhite(), 1.0f, &metadata),
+ applyRecovery(RgbWhite(), 1.0f, &metadata, displayBoost));
+ EXPECT_RGB_EQ(applyRecovery(RgbRed(), 1.0f, &metadata),
+ applyRecovery(RgbRed(), 1.0f, &metadata, displayBoost));
+ EXPECT_RGB_EQ(applyRecovery(RgbGreen(), 1.0f, &metadata),
+ applyRecovery(RgbGreen(), 1.0f, &metadata, displayBoost));
+ EXPECT_RGB_EQ(applyRecovery(RgbBlue(), 1.0f, &metadata),
+ applyRecovery(RgbBlue(), 1.0f, &metadata, displayBoost));
+ EXPECT_RGB_EQ(applyRecovery(e, 1.0f, &metadata),
+ applyRecovery(e, 1.0f, &metadata, displayBoost));
}
TEST_F(RecoveryMapMathTest, GetYuv420Pixel) {
@@ -981,8 +1028,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/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp
index 5965d41..e393fb2 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaRenderEngine.cpp
@@ -395,10 +395,14 @@
mRenderEngineType != RenderEngineType::SKIA_VK_THREADED) {
return;
}
- // We currently don't attempt to map a buffer if the buffer contains protected content
- // because GPU resources for protected buffers is much more limited.
+ // We don't attempt to map a buffer if the buffer contains protected content. In GL this is
+ // important because GPU resources for protected buffers are much more limited. (In Vk we
+ // simply match the existing behavior for protected buffers.) In Vk, we never cache any
+ // buffers while in a protected context, since Vk cannot share across contexts, and protected
+ // is less common.
const bool isProtectedBuffer = buffer->getUsage() & GRALLOC_USAGE_PROTECTED;
- if (isProtectedBuffer) {
+ if (isProtectedBuffer ||
+ (mRenderEngineType == RenderEngineType::SKIA_VK_THREADED && isProtected())) {
return;
}
ATRACE_CALL();
@@ -461,6 +465,20 @@
}
}
+std::shared_ptr<AutoBackendTexture::LocalRef> SkiaRenderEngine::getOrCreateBackendTexture(
+ const sp<GraphicBuffer>& buffer, bool isOutputBuffer) {
+ // Do not lookup the buffer in the cache for protected contexts with the SkiaVk back-end
+ if (mRenderEngineType == RenderEngineType::SKIA_GL_THREADED ||
+ (mRenderEngineType == RenderEngineType::SKIA_VK_THREADED && !isProtected())) {
+ if (const auto& it = mTextureCache.find(buffer->getId()); it != mTextureCache.end()) {
+ return it->second;
+ }
+ }
+ return std::make_shared<AutoBackendTexture::LocalRef>(getActiveGrContext(),
+ buffer->toAHardwareBuffer(),
+ isOutputBuffer, mTextureCleanupMgr);
+}
+
bool SkiaRenderEngine::canSkipPostRenderCleanup() const {
std::lock_guard<std::mutex> lock(mRenderingMutex);
return mTextureCleanupMgr.isEmpty();
@@ -651,21 +669,11 @@
validateOutputBufferUsage(buffer->getBuffer());
auto grContext = getActiveGrContext();
- auto& cache = mTextureCache;
// any AutoBackendTexture deletions will now be deferred until cleanupPostRender is called
DeferTextureCleanup dtc(mTextureCleanupMgr);
- std::shared_ptr<AutoBackendTexture::LocalRef> surfaceTextureRef;
- if (const auto& it = cache.find(buffer->getBuffer()->getId()); it != cache.end()) {
- surfaceTextureRef = it->second;
- } else {
- surfaceTextureRef =
- std::make_shared<AutoBackendTexture::LocalRef>(grContext,
- buffer->getBuffer()
- ->toAHardwareBuffer(),
- true, mTextureCleanupMgr);
- }
+ auto surfaceTextureRef = getOrCreateBackendTexture(buffer->getBuffer(), true);
// wait on the buffer to be ready to use prior to using it
waitFence(grContext, bufferFence);
@@ -904,21 +912,7 @@
ATRACE_NAME("DrawImage");
validateInputBufferUsage(layer.source.buffer.buffer->getBuffer());
const auto& item = layer.source.buffer;
- std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef = nullptr;
-
- if (const auto& iter = cache.find(item.buffer->getBuffer()->getId());
- iter != cache.end()) {
- imageTextureRef = iter->second;
- } else {
- // If we didn't find the image in the cache, then create a local ref but don't cache
- // it. If we're using skia, we're guaranteed to run on a dedicated GPU thread so if
- // we didn't find anything in the cache then we intentionally did not cache this
- // buffer's resources.
- imageTextureRef = std::make_shared<
- AutoBackendTexture::LocalRef>(grContext,
- item.buffer->getBuffer()->toAHardwareBuffer(),
- false, mTextureCleanupMgr);
- }
+ auto imageTextureRef = getOrCreateBackendTexture(item.buffer->getBuffer(), false);
// if the layer's buffer has a fence, then we must must respect the fence prior to using
// the buffer.
diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h
index dd6646b..e4406b4 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.h
+++ b/libs/renderengine/skia/SkiaRenderEngine.h
@@ -133,6 +133,8 @@
void unmapExternalTextureBuffer(sp<GraphicBuffer>&& buffer) override final;
bool canSkipPostRenderCleanup() const override final;
+ std::shared_ptr<AutoBackendTexture::LocalRef> getOrCreateBackendTexture(
+ const sp<GraphicBuffer>& buffer, bool isOutputBuffer) REQUIRES(mRenderingMutex);
void initCanvas(SkCanvas* canvas, const DisplaySettings& display);
void drawShadow(SkCanvas* canvas, const SkRRect& casterRRect,
const ShadowSettings& shadowSettings);
@@ -167,7 +169,9 @@
// Number of external holders of ExternalTexture references, per GraphicBuffer ID.
std::unordered_map<GraphicBufferId, int32_t> mGraphicBufferExternalRefs
GUARDED_BY(mRenderingMutex);
- // Cache of GL textures that we'll store per GraphicBuffer ID, shared between GPU contexts.
+ // For GL, this cache is shared between protected and unprotected contexts. For Vulkan, it is
+ // only used for the unprotected context, because Vulkan does not allow sharing between
+ // contexts, and protected is less common.
std::unordered_map<GraphicBufferId, std::shared_ptr<AutoBackendTexture::LocalRef>> mTextureCache
GUARDED_BY(mRenderingMutex);
std::unordered_map<shaders::LinearEffect, sk_sp<SkRuntimeEffect>, shaders::LinearEffectHasher>
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/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..95f819a 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,23 +54,16 @@
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;
- /* Sets a mask that indicates which buttons are pressed. */
- virtual void setButtonState(int32_t buttonState) = 0;
-
- /* Gets a mask that indicates which buttons are pressed. */
- virtual int32_t getButtonState() const = 0;
-
/* Sets the absolute location of the pointer. */
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..ddf6c87 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));
@@ -466,7 +465,7 @@
mHasMic, getAssociatedDisplayId().value_or(ADISPLAY_ID_NONE));
for_each_mapper(
- [&outDeviceInfo](InputMapper& mapper) { mapper.populateDeviceInfo(&outDeviceInfo); });
+ [&outDeviceInfo](InputMapper& mapper) { mapper.populateDeviceInfo(outDeviceInfo); });
if (mController) {
mController->populateDeviceInfo(&outDeviceInfo);
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index 13e4d0c..83cf287 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"
@@ -79,30 +81,31 @@
return mSource;
}
-void CursorInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
+void CursorInputMapper::populateDeviceInfo(InputDeviceInfo& info) {
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);
- info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale, 0.0f);
- info->addMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, mSource, -1.0f, 1.0f, 0.0f, mXScale,
- 0.0f);
- info->addMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale,
- 0.0f);
+ info.addMotionRange(AMOTION_EVENT_AXIS_X, mSource, -1.0f, 1.0f, 0.0f, mXScale, 0.0f);
+ info.addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale, 0.0f);
+ info.addMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, mSource, -1.0f, 1.0f, 0.0f, mXScale,
+ 0.0f);
+ info.addMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale,
+ 0.0f);
}
- info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mSource, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f);
+ info.addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mSource, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f);
if (mCursorScrollAccumulator.haveRelativeVWheel()) {
- info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
+ info.addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
}
if (mCursorScrollAccumulator.haveRelativeHWheel()) {
- info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
+ info.addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 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) {
@@ -371,15 +373,10 @@
if (moved) {
mPointerController->move(deltaX, deltaY);
}
-
- if (buttonsChanged) {
- mPointerController->setButtonState(currentButtonState);
- }
-
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/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h
index 939cceb..5f02203 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.h
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.h
@@ -57,7 +57,7 @@
virtual ~CursorInputMapper();
virtual uint32_t getSources() const override;
- virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
+ virtual void populateDeviceInfo(InputDeviceInfo& deviceInfo) override;
virtual void dump(std::string& dump) override;
[[nodiscard]] std::list<NotifyArgs> configure(nsecs_t when,
const InputReaderConfiguration* config,
diff --git a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp
index 2809939..a44d15b 100644
--- a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp
@@ -30,11 +30,11 @@
return AINPUT_SOURCE_STYLUS;
}
-void ExternalStylusInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
+void ExternalStylusInputMapper::populateDeviceInfo(InputDeviceInfo& info) {
InputMapper::populateDeviceInfo(info);
if (mRawPressureAxis.valid) {
- info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, AINPUT_SOURCE_STYLUS, 0.0f, 1.0f, 0.0f,
- 0.0f, 0.0f);
+ info.addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, AINPUT_SOURCE_STYLUS, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f);
}
}
diff --git a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h
index b6c9055..11b5315 100644
--- a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h
+++ b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h
@@ -30,7 +30,7 @@
virtual ~ExternalStylusInputMapper() = default;
uint32_t getSources() const override;
- void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
+ void populateDeviceInfo(InputDeviceInfo& deviceInfo) override;
void dump(std::string& dump) override;
[[nodiscard]] std::list<NotifyArgs> configure(nsecs_t when,
const InputReaderConfiguration* config,
diff --git a/services/inputflinger/reader/mapper/InputMapper.cpp b/services/inputflinger/reader/mapper/InputMapper.cpp
index ba2ea99..9cf3696 100644
--- a/services/inputflinger/reader/mapper/InputMapper.cpp
+++ b/services/inputflinger/reader/mapper/InputMapper.cpp
@@ -29,8 +29,8 @@
InputMapper::~InputMapper() {}
-void InputMapper::populateDeviceInfo(InputDeviceInfo* info) {
- info->addSource(getSources());
+void InputMapper::populateDeviceInfo(InputDeviceInfo& info) {
+ info.addSource(getSources());
}
void InputMapper::dump(std::string& dump) {}
diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h
index 104305b..2722edd 100644
--- a/services/inputflinger/reader/mapper/InputMapper.h
+++ b/services/inputflinger/reader/mapper/InputMapper.h
@@ -51,7 +51,7 @@
inline InputReaderPolicyInterface* getPolicy() { return getContext()->getPolicy(); }
virtual uint32_t getSources() const = 0;
- virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
+ virtual void populateDeviceInfo(InputDeviceInfo& deviceInfo);
virtual void dump(std::string& dump);
[[nodiscard]] virtual std::list<NotifyArgs> configure(nsecs_t when,
const InputReaderConfiguration* config,
diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
index d7f8b17..7724cf7 100644
--- a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
@@ -29,7 +29,7 @@
return AINPUT_SOURCE_JOYSTICK;
}
-void JoystickInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
+void JoystickInputMapper::populateDeviceInfo(InputDeviceInfo& info) {
InputMapper::populateDeviceInfo(info);
for (const auto& [_, axis] : mAxes) {
@@ -41,16 +41,16 @@
}
}
-void JoystickInputMapper::addMotionRange(int32_t axisId, const Axis& axis, InputDeviceInfo* info) {
- info->addMotionRange(axisId, AINPUT_SOURCE_JOYSTICK, axis.min, axis.max, axis.flat, axis.fuzz,
- axis.resolution);
+void JoystickInputMapper::addMotionRange(int32_t axisId, const Axis& axis, InputDeviceInfo& info) {
+ info.addMotionRange(axisId, AINPUT_SOURCE_JOYSTICK, axis.min, axis.max, axis.flat, axis.fuzz,
+ axis.resolution);
/* In order to ease the transition for developers from using the old axes
* to the newer, more semantically correct axes, we'll continue to register
* the old axes as duplicates of their corresponding new ones. */
int32_t compatAxis = getCompatAxis(axisId);
if (compatAxis >= 0) {
- info->addMotionRange(compatAxis, AINPUT_SOURCE_JOYSTICK, axis.min, axis.max, axis.flat,
- axis.fuzz, axis.resolution);
+ info.addMotionRange(compatAxis, AINPUT_SOURCE_JOYSTICK, axis.min, axis.max, axis.flat,
+ axis.fuzz, axis.resolution);
}
}
diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.h b/services/inputflinger/reader/mapper/JoystickInputMapper.h
index 72b8a52..9ca4176 100644
--- a/services/inputflinger/reader/mapper/JoystickInputMapper.h
+++ b/services/inputflinger/reader/mapper/JoystickInputMapper.h
@@ -26,7 +26,7 @@
virtual ~JoystickInputMapper();
virtual uint32_t getSources() const override;
- virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
+ virtual void populateDeviceInfo(InputDeviceInfo& deviceInfo) override;
virtual void dump(std::string& dump) override;
[[nodiscard]] std::list<NotifyArgs> configure(nsecs_t when,
const InputReaderConfiguration* config,
@@ -106,7 +106,7 @@
static bool isCenteredAxis(int32_t axis);
static int32_t getCompatAxis(int32_t axis);
- static void addMotionRange(int32_t axisId, const Axis& axis, InputDeviceInfo* info);
+ static void addMotionRange(int32_t axisId, const Axis& axis, InputDeviceInfo& info);
static void setPointerCoordsAxisValue(PointerCoords* pointerCoords, int32_t axis, float value);
};
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
index dc0454d..269c106 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -85,18 +85,18 @@
return ADISPLAY_ID_NONE;
}
-void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
+void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo& info) {
InputMapper::populateDeviceInfo(info);
- info->setKeyboardType(mKeyboardType);
- info->setKeyCharacterMap(getDeviceContext().getKeyCharacterMap());
+ info.setKeyboardType(mKeyboardType);
+ info.setKeyCharacterMap(getDeviceContext().getKeyCharacterMap());
if (mKeyboardLayoutInfo) {
- info->setKeyboardLayoutInfo(*mKeyboardLayoutInfo);
+ info.setKeyboardLayoutInfo(*mKeyboardLayoutInfo);
} else {
std::optional<RawLayoutInfo> layoutInfo = getDeviceContext().getRawLayoutInfo();
if (layoutInfo) {
- info->setKeyboardLayoutInfo(
+ info.setKeyboardLayoutInfo(
KeyboardLayoutInfo(layoutInfo->languageTag, layoutInfo->layoutType));
}
}
@@ -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/KeyboardInputMapper.h b/services/inputflinger/reader/mapper/KeyboardInputMapper.h
index da5b8ee..2fc82c3 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.h
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.h
@@ -27,7 +27,7 @@
~KeyboardInputMapper() override = default;
uint32_t getSources() const override;
- void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
+ void populateDeviceInfo(InputDeviceInfo& deviceInfo) override;
void dump(std::string& dump) override;
[[nodiscard]] std::list<NotifyArgs> configure(nsecs_t when,
const InputReaderConfiguration* config,
diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
index 19a79d7..94cc145 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 {
@@ -35,22 +37,23 @@
return mSource;
}
-void RotaryEncoderInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
+void RotaryEncoderInputMapper::populateDeviceInfo(InputDeviceInfo& info) {
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;
}
- info->addMotionRange(AMOTION_EVENT_AXIS_SCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f,
- res * mScalingFactor);
+ mScalingFactor = scalingFactor.value_or(1.0f);
+ info.addMotionRange(AMOTION_EVENT_AXIS_SCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f,
+ res.value_or(0.0f) * mScalingFactor);
}
}
diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h
index cb5fd88..a0516c4 100644
--- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h
+++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h
@@ -29,7 +29,7 @@
virtual ~RotaryEncoderInputMapper();
virtual uint32_t getSources() const override;
- virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
+ virtual void populateDeviceInfo(InputDeviceInfo& deviceInfo) override;
virtual void dump(std::string& dump) override;
[[nodiscard]] std::list<NotifyArgs> configure(nsecs_t when,
const InputReaderConfiguration* config,
diff --git a/services/inputflinger/reader/mapper/SensorInputMapper.cpp b/services/inputflinger/reader/mapper/SensorInputMapper.cpp
index 3d60bfd..60e6727 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);
@@ -79,12 +73,12 @@
}
}
-void SensorInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
+void SensorInputMapper::populateDeviceInfo(InputDeviceInfo& info) {
InputMapper::populateDeviceInfo(info);
for (const auto& [sensorType, sensor] : mSensors) {
- info->addSensorInfo(sensor.sensorInfo);
- info->setHasSensor(true);
+ info.addSensorInfo(sensor.sensorInfo);
+ info.setHasSensor(true);
}
}
@@ -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..7f47df7 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 {
@@ -28,7 +31,7 @@
~SensorInputMapper() override;
uint32_t getSources() const override;
- void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
+ void populateDeviceInfo(InputDeviceInfo& deviceInfo) override;
void dump(std::string& dump) override;
[[nodiscard]] std::list<NotifyArgs> configure(nsecs_t when,
const InputReaderConfiguration* config,
@@ -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 96c163d..df7ba49 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -134,16 +134,16 @@
return mSource;
}
-void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
+void TouchInputMapper::populateDeviceInfo(InputDeviceInfo& info) {
InputMapper::populateDeviceInfo(info);
if (mDeviceMode == DeviceMode::DISABLED) {
return;
}
- info->addMotionRange(mOrientedRanges.x);
- info->addMotionRange(mOrientedRanges.y);
- info->addMotionRange(mOrientedRanges.pressure);
+ info.addMotionRange(mOrientedRanges.x);
+ info.addMotionRange(mOrientedRanges.y);
+ info.addMotionRange(mOrientedRanges.pressure);
if (mDeviceMode == DeviceMode::UNSCALED && mSource == AINPUT_SOURCE_TOUCHPAD) {
// Populate RELATIVE_X and RELATIVE_Y motion ranges for touchpad capture mode.
@@ -153,46 +153,46 @@
// touchpad in one sample cycle.
const InputDeviceInfo::MotionRange& x = mOrientedRanges.x;
const InputDeviceInfo::MotionRange& y = mOrientedRanges.y;
- info->addMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, mSource, -x.max, x.max, x.flat, x.fuzz,
- x.resolution);
- info->addMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, mSource, -y.max, y.max, y.flat, y.fuzz,
- y.resolution);
+ info.addMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, mSource, -x.max, x.max, x.flat, x.fuzz,
+ x.resolution);
+ info.addMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, mSource, -y.max, y.max, y.flat, y.fuzz,
+ y.resolution);
}
if (mOrientedRanges.size) {
- info->addMotionRange(*mOrientedRanges.size);
+ info.addMotionRange(*mOrientedRanges.size);
}
if (mOrientedRanges.touchMajor) {
- info->addMotionRange(*mOrientedRanges.touchMajor);
- info->addMotionRange(*mOrientedRanges.touchMinor);
+ info.addMotionRange(*mOrientedRanges.touchMajor);
+ info.addMotionRange(*mOrientedRanges.touchMinor);
}
if (mOrientedRanges.toolMajor) {
- info->addMotionRange(*mOrientedRanges.toolMajor);
- info->addMotionRange(*mOrientedRanges.toolMinor);
+ info.addMotionRange(*mOrientedRanges.toolMajor);
+ info.addMotionRange(*mOrientedRanges.toolMinor);
}
if (mOrientedRanges.orientation) {
- info->addMotionRange(*mOrientedRanges.orientation);
+ info.addMotionRange(*mOrientedRanges.orientation);
}
if (mOrientedRanges.distance) {
- info->addMotionRange(*mOrientedRanges.distance);
+ info.addMotionRange(*mOrientedRanges.distance);
}
if (mOrientedRanges.tilt) {
- info->addMotionRange(*mOrientedRanges.tilt);
+ info.addMotionRange(*mOrientedRanges.tilt);
}
if (mCursorScrollAccumulator.haveRelativeVWheel()) {
- info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
+ info.addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
}
if (mCursorScrollAccumulator.haveRelativeHWheel()) {
- info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
+ info.addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
}
- info->setButtonUnderPad(mParameters.hasButtonUnderPad);
- info->setUsiVersion(mParameters.usiVersion);
+ info.setButtonUnderPad(mParameters.hasButtonUnderPad);
+ info.setUsiVersion(mParameters.usiVersion);
}
void TouchInputMapper::dump(std::string& dump) {
@@ -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;
@@ -1160,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() {
@@ -1675,7 +1658,6 @@
mPointerController->setPresentation(PointerControllerInterface::Presentation::SPOT);
mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
- mPointerController->setButtonState(mCurrentRawState.buttonState);
mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords.cbegin(),
mCurrentCookedState.cookedPointerData.idToIndex.cbegin(),
mCurrentCookedState.cookedPointerData.touchingIdBits |
@@ -2691,8 +2673,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();
@@ -2898,8 +2879,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();
@@ -2925,8 +2905,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");
@@ -2988,8 +2967,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;
@@ -3025,8 +3003,7 @@
down = false;
}
- float x, y;
- mPointerController->getPosition(&x, &y);
+ const auto [x, y] = mPointerController->getPosition();
mPointerGesture.currentGestureIdBits.clear();
mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
@@ -3051,8 +3028,6 @@
prepareMultiFingerPointerGestures(when, outCancelPreviousGesture, outFinishPreviousGesture);
}
- mPointerController->setButtonState(mCurrentRawState.buttonState);
-
if (DEBUG_GESTURES) {
ALOGD("Gestures: finishPreviousGesture=%s, cancelPreviousGesture=%s, "
"currentGestureMode=%d, currentGestureIdBits=0x%08x, "
@@ -3193,8 +3168,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.
@@ -3509,8 +3484,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);
@@ -3548,9 +3522,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);
@@ -3590,15 +3563,13 @@
if (down || hovering) {
mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER);
mPointerController->clearSpots();
- mPointerController->setButtonState(mCurrentRawState.buttonState);
mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
} else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) {
mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
}
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;
@@ -3819,7 +3790,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..ae7faa9 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>
@@ -147,7 +150,7 @@
~TouchInputMapper() override;
uint32_t getSources() const override;
- void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
+ void populateDeviceInfo(InputDeviceInfo& deviceInfo) override;
void dump(std::string& dump) override;
[[nodiscard]] std::list<NotifyArgs> configure(nsecs_t when,
const InputReaderConfiguration* config,
diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
index d3af402..ec4bc21 100644
--- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
@@ -20,6 +20,7 @@
#include <optional>
#include <android/input.h>
+#include <ftl/enum.h>
#include <input/PrintTools.h>
#include <linux/input-event-codes.h>
#include <log/log_main.h>
@@ -205,6 +206,11 @@
return AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD;
}
+void TouchpadInputMapper::populateDeviceInfo(InputDeviceInfo& info) {
+ InputMapper::populateDeviceInfo(info);
+ mGestureConverter.populateMotionRanges(info);
+}
+
void TouchpadInputMapper::dump(std::string& dump) {
dump += INDENT2 "Touchpad Input Mapper:\n";
dump += INDENT3 "Gesture converter:\n";
@@ -216,6 +222,11 @@
std::list<NotifyArgs> TouchpadInputMapper::configure(nsecs_t when,
const InputReaderConfiguration* config,
uint32_t changes) {
+ if (!changes) {
+ // First time configuration
+ mPropertyProvider.loadPropertiesFromIdcFile(getDeviceContext().getConfiguration());
+ }
+
if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
std::optional<int32_t> displayId = mPointerController->getDisplayId();
ui::Rotation orientation = ui::ROTATION_0;
diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.h b/services/inputflinger/reader/mapper/TouchpadInputMapper.h
index d693bca..fb36d92 100644
--- a/services/inputflinger/reader/mapper/TouchpadInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.h
@@ -41,6 +41,7 @@
~TouchpadInputMapper();
uint32_t getSources() const override;
+ void populateDeviceInfo(InputDeviceInfo& deviceInfo) override;
void dump(std::string& dump) override;
[[nodiscard]] std::list<NotifyArgs> configure(nsecs_t when,
diff --git a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
index 7645b12..2c77fc4 100644
--- a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
@@ -29,10 +29,10 @@
return 0;
}
-void VibratorInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
+void VibratorInputMapper::populateDeviceInfo(InputDeviceInfo& info) {
InputMapper::populateDeviceInfo(info);
- info->setVibrator(true);
+ info.setVibrator(true);
}
std::list<NotifyArgs> VibratorInputMapper::process(const RawEvent* rawEvent) {
diff --git a/services/inputflinger/reader/mapper/VibratorInputMapper.h b/services/inputflinger/reader/mapper/VibratorInputMapper.h
index e98f63a..e665973 100644
--- a/services/inputflinger/reader/mapper/VibratorInputMapper.h
+++ b/services/inputflinger/reader/mapper/VibratorInputMapper.h
@@ -26,7 +26,7 @@
virtual ~VibratorInputMapper();
virtual uint32_t getSources() const override;
- virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
+ virtual void populateDeviceInfo(InputDeviceInfo& deviceInfo) override;
[[nodiscard]] std::list<NotifyArgs> process(const RawEvent* rawEvent) override;
[[nodiscard]] std::list<NotifyArgs> vibrate(const VibrationSequence& sequence, ssize_t repeat,
diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
index d636d44..707b1f3 100644
--- a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
@@ -16,13 +16,14 @@
#include "gestures/GestureConverter.h"
+#include <optional>
#include <sstream>
#include <android-base/stringprintf.h>
-#include <android/input.h>
#include <ftl/enum.h>
#include <linux/input-event-codes.h>
#include <log/log_main.h>
+#include <ui/FloatRect.h>
#include "TouchCursorInputMapperCommon.h"
#include "input/Input.h"
@@ -75,6 +76,28 @@
mButtonState = 0;
}
+void GestureConverter::populateMotionRanges(InputDeviceInfo& info) const {
+ info.addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, SOURCE, 0.0f, 1.0f, 0, 0, 0);
+
+ // TODO(b/259547750): set this using the raw axis ranges from the touchpad when pointer capture
+ // is enabled.
+ if (std::optional<FloatRect> rect = mPointerController->getBounds(); rect.has_value()) {
+ info.addMotionRange(AMOTION_EVENT_AXIS_X, SOURCE, rect->left, rect->right, 0, 0, 0);
+ info.addMotionRange(AMOTION_EVENT_AXIS_Y, SOURCE, rect->top, rect->bottom, 0, 0, 0);
+ }
+
+ info.addMotionRange(AMOTION_EVENT_AXIS_GESTURE_X_OFFSET, SOURCE, -1.0f, 1.0f, 0, 0, 0);
+ info.addMotionRange(AMOTION_EVENT_AXIS_GESTURE_Y_OFFSET, SOURCE, -1.0f, 1.0f, 0, 0, 0);
+
+ // The other axes that can be reported don't have ranges that are easy to define. RELATIVE_X/Y
+ // and GESTURE_SCROLL_X/Y_DISTANCE are the result of acceleration functions being applied to
+ // finger movements, so their maximum values can't simply be derived from the size of the
+ // touchpad. GESTURE_PINCH_SCALE_FACTOR's maximum value depends on the minimum finger separation
+ // that the pad can report, which cannot be determined from its raw axis information. (Assuming
+ // a minimum finger separation of 1 unit would let us calculate a theoretical maximum, but it
+ // would be orders of magnitude too high, so probably not very useful.)
+}
+
std::list<NotifyArgs> GestureConverter::handleGesture(nsecs_t when, nsecs_t readTime,
const Gesture& gesture) {
switch (gesture.type) {
@@ -98,7 +121,6 @@
case kGestureTypePinch:
return handlePinch(when, readTime, gesture);
default:
- // TODO(b/251196347): handle more gesture types.
return {};
}
}
@@ -111,8 +133,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 +158,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 +223,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 +246,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 +264,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 +281,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 +317,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 +327,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 +343,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 +367,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
@@ -421,10 +441,7 @@
const PointerProperties* pointerProperties,
const PointerCoords* pointerCoords,
float xCursorPosition, float yCursorPosition) {
- // TODO(b/260226362): consider what the appropriate source for these events is.
- const uint32_t source = AINPUT_SOURCE_MOUSE;
-
- return NotifyMotionArgs(mReaderContext.getNextId(), when, readTime, mDeviceId, source,
+ return NotifyMotionArgs(mReaderContext.getNextId(), when, readTime, mDeviceId, SOURCE,
mPointerController->getDisplayId(), /* policyFlags= */ POLICY_FLAG_WAKE,
action, /* actionButton= */ actionButton, /* flags= */ 0,
mReaderContext.getGlobalMetaState(), buttonState,
diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.h b/services/inputflinger/reader/mapper/gestures/GestureConverter.h
index 2ec5841..a10dcce 100644
--- a/services/inputflinger/reader/mapper/gestures/GestureConverter.h
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.h
@@ -21,6 +21,7 @@
#include <memory>
#include <PointerControllerInterface.h>
+#include <android/input.h>
#include <utils/Timers.h>
#include "EventHub.h"
@@ -45,6 +46,8 @@
void setOrientation(ui::Rotation orientation) { mOrientation = orientation; }
void reset();
+ void populateMotionRanges(InputDeviceInfo& info) const;
+
[[nodiscard]] std::list<NotifyArgs> handleGesture(nsecs_t when, nsecs_t readTime,
const Gesture& gesture);
@@ -98,6 +101,9 @@
{.id = 3, .toolType = AMOTION_EVENT_TOOL_TYPE_FINGER},
}};
std::array<PointerCoords, MAX_FAKE_FINGERS> mFakeFingerCoords = {};
+
+ // TODO(b/260226362): consider what the appropriate source for these events is.
+ static constexpr uint32_t SOURCE = AINPUT_SOURCE_MOUSE;
};
} // namespace android
diff --git a/services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp b/services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp
index 089f45a..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>
@@ -84,6 +85,29 @@
return dump;
}
+void PropertyProvider::loadPropertiesFromIdcFile(const PropertyMap& idcProperties) {
+ // For compatibility with the configuration file syntax, gesture property names in IDC files are
+ // prefixed with "gestureProp." and have spaces replaced by underscores. So, for example, the
+ // configuration key "gestureProp.Palm_Width" refers to the "Palm Width" property.
+ const std::string gesturePropPrefix = "gestureProp.";
+ for (const std::string key : idcProperties.getKeysWithPrefix(gesturePropPrefix)) {
+ std::string propertyName = key.substr(gesturePropPrefix.length());
+ for (size_t i = 0; i < propertyName.length(); i++) {
+ if (propertyName[i] == '_') {
+ propertyName[i] = ' ';
+ }
+ }
+
+ auto it = mProperties.find(propertyName);
+ if (it != mProperties.end()) {
+ it->second.trySetFromIdcProperty(idcProperties, key);
+ } else {
+ ALOGE("Gesture property \"%s\" specified in IDC file does not exist for this device.",
+ propertyName.c_str());
+ }
+ }
+}
+
GesturesProp* PropertyProvider::createIntArrayProperty(const std::string& name, int* loc,
size_t count, const int* init) {
const auto [it, inserted] =
@@ -211,6 +235,57 @@
setValues(std::get<double*>(mDataPointer), values);
}
+namespace {
+
+// Helper to std::visit with lambdas.
+template <typename... V>
+struct Visitor : V... {};
+// explicit deduction guide (not needed as of C++20)
+template <typename... V>
+Visitor(V...) -> Visitor<V...>;
+
+} // namespace
+
+void GesturesProp::trySetFromIdcProperty(const android::PropertyMap& idcProperties,
+ const std::string& propertyName) {
+ if (mCount != 1) {
+ ALOGE("Gesture property \"%s\" is an array, and so cannot be set in an IDC file.",
+ mName.c_str());
+ return;
+ }
+ bool parsedSuccessfully = false;
+ Visitor setVisitor{
+ [&](int*) {
+ if (std::optional<int32_t> value = idcProperties.getInt(propertyName); value) {
+ parsedSuccessfully = true;
+ setIntValues({*value});
+ }
+ },
+ [&](GesturesPropBool*) {
+ if (std::optional<bool> value = idcProperties.getBool(propertyName); value) {
+ parsedSuccessfully = true;
+ setBoolValues({*value});
+ }
+ },
+ [&](double*) {
+ 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\" couldn't be set due to a type mismatch.",
+ mName.c_str());
+}
+
template <typename T, typename U>
const std::vector<T> GesturesProp::getValues(U* dataPointer) const {
if (mGetter != nullptr) {
diff --git a/services/inputflinger/reader/mapper/gestures/PropertyProvider.h b/services/inputflinger/reader/mapper/gestures/PropertyProvider.h
index 50451a3..c7e0858 100644
--- a/services/inputflinger/reader/mapper/gestures/PropertyProvider.h
+++ b/services/inputflinger/reader/mapper/gestures/PropertyProvider.h
@@ -22,6 +22,7 @@
#include <vector>
#include "include/gestures.h"
+#include "input/PropertyMap.h"
namespace android {
@@ -35,6 +36,8 @@
GesturesProp& getProperty(const std::string& name);
std::string dump() const;
+ void loadPropertiesFromIdcFile(const PropertyMap& idcProperties);
+
// Methods to be called by the gestures library:
GesturesProp* createIntArrayProperty(const std::string& name, int* loc, size_t count,
const int* init);
@@ -83,6 +86,9 @@
// Setting string values isn't supported since we don't have a use case yet and the memory
// management adds additional complexity.
+ void trySetFromIdcProperty(const android::PropertyMap& idcProperties,
+ const std::string& propertyName);
+
private:
// Two type parameters are required for these methods, rather than one, due to the gestures
// library using its own bool type.
diff --git a/services/inputflinger/tests/FakePointerController.cpp b/services/inputflinger/tests/FakePointerController.cpp
index 28dad95..ca517f3 100644
--- a/services/inputflinger/tests/FakePointerController.cpp
+++ b/services/inputflinger/tests/FakePointerController.cpp
@@ -37,17 +37,8 @@
mY = y;
}
-void FakePointerController::setButtonState(int32_t buttonState) {
- mButtonState = buttonState;
-}
-
-int32_t FakePointerController::getButtonState() const {
- 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 +50,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 +59,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..c374267 100644
--- a/services/inputflinger/tests/FakePointerController.h
+++ b/services/inputflinger/tests/FakePointerController.h
@@ -32,9 +32,7 @@
const std::map<int32_t, std::vector<int32_t>>& getSpots();
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 +40,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;
@@ -54,7 +52,6 @@
bool mHaveBounds{false};
float mMinX{0}, mMinY{0}, mMaxX{0}, mMaxY{0};
float mX{0}, mY{0};
- int32_t mButtonState{0};
int32_t mDisplayId{ADISPLAY_ID_DEFAULT};
bool mIsPointerShown{false};
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/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 711cfbf..853c5b0 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>
@@ -122,7 +123,7 @@
static void assertAxisResolution(MultiTouchInputMapper& mapper, int axis, float resolution) {
InputDeviceInfo info;
- mapper.populateDeviceInfo(&info);
+ mapper.populateDeviceInfo(info);
const InputDeviceInfo::MotionRange* motionRange =
info.getMotionRange(axis, AINPUT_SOURCE_TOUCHSCREEN);
@@ -131,7 +132,7 @@
static void assertAxisNotPresent(MultiTouchInputMapper& mapper, int axis) {
InputDeviceInfo info;
- mapper.populateDeviceInfo(&info);
+ mapper.populateDeviceInfo(info);
const InputDeviceInfo::MotionRange* motionRange =
info.getMotionRange(axis, AINPUT_SOURCE_TOUCHSCREEN);
@@ -254,11 +255,11 @@
private:
uint32_t getSources() const override { return mSources; }
- void populateDeviceInfo(InputDeviceInfo* deviceInfo) override {
+ void populateDeviceInfo(InputDeviceInfo& deviceInfo) override {
InputMapper::populateDeviceInfo(deviceInfo);
if (mKeyboardType != AINPUT_KEYBOARD_TYPE_NONE) {
- deviceInfo->setKeyboardType(mKeyboardType);
+ deviceInfo.setKeyboardType(mKeyboardType);
}
}
@@ -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());
@@ -3807,7 +3808,7 @@
CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
InputDeviceInfo info;
- mapper.populateDeviceInfo(&info);
+ mapper.populateDeviceInfo(info);
// Initially there may not be a valid motion range.
ASSERT_EQ(nullptr, info.getMotionRange(AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_MOUSE));
@@ -3819,7 +3820,7 @@
mFakePointerController->setBounds(1, 2, 800 - 1, 480 - 1);
InputDeviceInfo info2;
- mapper.populateDeviceInfo(&info2);
+ mapper.populateDeviceInfo(info2);
ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2,
AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_MOUSE,
@@ -3837,7 +3838,7 @@
CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
InputDeviceInfo info;
- mapper.populateDeviceInfo(&info);
+ mapper.populateDeviceInfo(info);
ASSERT_NO_FATAL_FAILURE(assertMotionRange(info,
AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_TRACKBALL,
@@ -4113,7 +4114,6 @@
mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1);
mFakePointerController->setPosition(100, 200);
- mFakePointerController->setButtonState(0);
NotifyMotionArgs motionArgs;
NotifyKeyArgs keyArgs;
@@ -4124,14 +4124,12 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, motionArgs.buttonState);
- ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, mFakePointerController->getButtonState());
ASSERT_NO_FATAL_FAILURE(
assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 1.0f));
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_PRESS, motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, motionArgs.buttonState);
- ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, mFakePointerController->getButtonState());
ASSERT_NO_FATAL_FAILURE(
assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 1.0f));
@@ -4140,21 +4138,18 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_RELEASE, motionArgs.action);
ASSERT_EQ(0, motionArgs.buttonState);
- ASSERT_EQ(0, mFakePointerController->getButtonState());
ASSERT_NO_FATAL_FAILURE(
assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f));
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action);
ASSERT_EQ(0, motionArgs.buttonState);
- ASSERT_EQ(0, mFakePointerController->getButtonState());
ASSERT_NO_FATAL_FAILURE(
assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f));
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
ASSERT_EQ(0, motionArgs.buttonState);
- ASSERT_EQ(0, mFakePointerController->getButtonState());
ASSERT_NO_FATAL_FAILURE(
assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f));
@@ -4165,26 +4160,20 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY | AMOTION_EVENT_BUTTON_TERTIARY,
- motionArgs.buttonState);
- ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY | AMOTION_EVENT_BUTTON_TERTIARY,
- mFakePointerController->getButtonState());
+ motionArgs.buttonState);
ASSERT_NO_FATAL_FAILURE(
assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 1.0f));
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_PRESS, motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState);
- ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY | AMOTION_EVENT_BUTTON_TERTIARY,
- mFakePointerController->getButtonState());
ASSERT_NO_FATAL_FAILURE(
assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 1.0f));
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_PRESS, motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY | AMOTION_EVENT_BUTTON_TERTIARY,
- motionArgs.buttonState);
- ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY | AMOTION_EVENT_BUTTON_TERTIARY,
- mFakePointerController->getButtonState());
+ motionArgs.buttonState);
ASSERT_NO_FATAL_FAILURE(
assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 1.0f));
@@ -4193,14 +4182,12 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_RELEASE, motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState);
- ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, mFakePointerController->getButtonState());
ASSERT_NO_FATAL_FAILURE(
assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 1.0f));
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState);
- ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, mFakePointerController->getButtonState());
ASSERT_NO_FATAL_FAILURE(
assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 1.0f));
@@ -4209,7 +4196,6 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_RELEASE, motionArgs.action);
ASSERT_EQ(0, motionArgs.buttonState);
- ASSERT_EQ(0, mFakePointerController->getButtonState());
ASSERT_NO_FATAL_FAILURE(
assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f));
process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, BTN_MIDDLE, 0);
@@ -4217,14 +4203,12 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(0, motionArgs.buttonState);
- ASSERT_EQ(0, mFakePointerController->getButtonState());
ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action);
ASSERT_NO_FATAL_FAILURE(
assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f));
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(0, motionArgs.buttonState);
- ASSERT_EQ(0, mFakePointerController->getButtonState());
ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
ASSERT_NO_FATAL_FAILURE(
assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f));
@@ -4239,14 +4223,12 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState);
- ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, mFakePointerController->getButtonState());
ASSERT_NO_FATAL_FAILURE(
assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f));
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_PRESS, motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState);
- ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, mFakePointerController->getButtonState());
ASSERT_NO_FATAL_FAILURE(
assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f));
@@ -4255,14 +4237,12 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_RELEASE, motionArgs.action);
ASSERT_EQ(0, motionArgs.buttonState);
- ASSERT_EQ(0, mFakePointerController->getButtonState());
ASSERT_NO_FATAL_FAILURE(
assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f));
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
ASSERT_EQ(0, motionArgs.buttonState);
- ASSERT_EQ(0, mFakePointerController->getButtonState());
ASSERT_NO_FATAL_FAILURE(
assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f));
@@ -4280,14 +4260,12 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState);
- ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, mFakePointerController->getButtonState());
ASSERT_NO_FATAL_FAILURE(
assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f));
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_PRESS, motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState);
- ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, mFakePointerController->getButtonState());
ASSERT_NO_FATAL_FAILURE(
assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f));
@@ -4296,14 +4274,12 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_RELEASE, motionArgs.action);
ASSERT_EQ(0, motionArgs.buttonState);
- ASSERT_EQ(0, mFakePointerController->getButtonState());
ASSERT_NO_FATAL_FAILURE(
assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f));
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
ASSERT_EQ(0, motionArgs.buttonState);
- ASSERT_EQ(0, mFakePointerController->getButtonState());
ASSERT_NO_FATAL_FAILURE(
assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f));
@@ -4321,14 +4297,12 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState);
- ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, mFakePointerController->getButtonState());
ASSERT_NO_FATAL_FAILURE(
assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f));
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_PRESS, motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState);
- ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, mFakePointerController->getButtonState());
ASSERT_NO_FATAL_FAILURE(
assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f));
@@ -4337,14 +4311,12 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_RELEASE, motionArgs.action);
ASSERT_EQ(0, motionArgs.buttonState);
- ASSERT_EQ(0, mFakePointerController->getButtonState());
ASSERT_NO_FATAL_FAILURE(
assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f));
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
ASSERT_EQ(0, motionArgs.buttonState);
- ASSERT_EQ(0, mFakePointerController->getButtonState());
ASSERT_NO_FATAL_FAILURE(
assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f));
@@ -4362,14 +4334,12 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState);
- ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, mFakePointerController->getButtonState());
ASSERT_NO_FATAL_FAILURE(
assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f));
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_PRESS, motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState);
- ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, mFakePointerController->getButtonState());
ASSERT_NO_FATAL_FAILURE(
assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f));
@@ -4378,14 +4348,12 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_RELEASE, motionArgs.action);
ASSERT_EQ(0, motionArgs.buttonState);
- ASSERT_EQ(0, mFakePointerController->getButtonState());
ASSERT_NO_FATAL_FAILURE(
assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f));
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
ASSERT_EQ(0, motionArgs.buttonState);
- ASSERT_EQ(0, mFakePointerController->getButtonState());
ASSERT_NO_FATAL_FAILURE(
assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f));
@@ -4400,7 +4368,6 @@
mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1);
mFakePointerController->setPosition(100, 200);
- mFakePointerController->setButtonState(0);
NotifyMotionArgs args;
@@ -4427,7 +4394,6 @@
mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1);
mFakePointerController->setPosition(100, 200);
- mFakePointerController->setButtonState(0);
NotifyMotionArgs args;
@@ -4606,7 +4572,6 @@
mFakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1);
mFakePointerController->setPosition(100, 200);
- mFakePointerController->setButtonState(0);
// Ensure input events are generated for the secondary display.
process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 10);
@@ -4634,7 +4599,6 @@
mFakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1);
mFakePointerController->setPosition(100, 200);
- mFakePointerController->setButtonState(0);
process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 10);
process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, 20);
@@ -8480,7 +8444,7 @@
MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
InputDeviceInfo info;
- mapper.populateDeviceInfo(&info);
+ mapper.populateDeviceInfo(info);
ASSERT_NO_FATAL_FAILURE(assertMotionRange(info,
AINPUT_MOTION_RANGE_PRESSURE, AINPUT_SOURCE_TOUCHSCREEN,
0.0f, RAW_PRESSURE_MAX * 0.01, 0.0f, 0.0f));
@@ -9163,7 +9127,6 @@
std::make_shared<FakePointerController>();
fakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1);
fakePointerController->setPosition(100, 200);
- fakePointerController->setButtonState(0);
mFakePolicy->setPointerController(fakePointerController);
mFakePolicy->setDefaultPointerDisplayId(SECONDARY_DISPLAY_ID);
@@ -10158,7 +10121,6 @@
std::make_shared<FakePointerController>();
fakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1);
fakePointerController->setPosition(0, 0);
- fakePointerController->setButtonState(0);
// prepare device and capture
prepareDisplay(ui::ROTATION_0);
@@ -10308,7 +10270,6 @@
std::make_shared<FakePointerController>();
fakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1);
fakePointerController->setPosition(0, 0);
- fakePointerController->setButtonState(0);
// prepare device and capture
prepareDisplay(ui::ROTATION_0);
@@ -10448,7 +10409,6 @@
std::make_shared<FakePointerController>();
fakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1);
fakePointerController->setPosition(0, 0);
- fakePointerController->setButtonState(0);
prepareDisplay(ui::ROTATION_0);
prepareAxes(POSITION);
diff --git a/services/inputflinger/tests/PropertyProvider_test.cpp b/services/inputflinger/tests/PropertyProvider_test.cpp
index 42a6a9f..8a40e78 100644
--- a/services/inputflinger/tests/PropertyProvider_test.cpp
+++ b/services/inputflinger/tests/PropertyProvider_test.cpp
@@ -18,6 +18,7 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include "TestConstants.h"
#include "include/gestures.h"
namespace android {
@@ -283,4 +284,68 @@
EXPECT_FALSE(mProvider.hasProperty("Foo"));
}
+class PropertyProviderIdcLoadingTest : public testing::Test {
+protected:
+ void SetUp() override {
+ int initialInt = 0;
+ GesturesPropBool initialBool = false;
+ double initialReal = 0.0;
+ gesturePropProvider.create_int_fn(&mProvider, "An Integer", &mIntData, 1, &initialInt);
+ gesturePropProvider.create_bool_fn(&mProvider, "A Boolean", &mBoolData, 1, &initialBool);
+ gesturePropProvider.create_real_fn(&mProvider, "A Real", &mRealData, 1, &initialReal);
+ }
+
+ PropertyProvider mProvider;
+
+ int mIntData;
+ GesturesPropBool mBoolData;
+ double mRealData;
+};
+
+TEST_F(PropertyProviderIdcLoadingTest, AllCorrect) {
+ PropertyMap idcProps;
+ idcProps.addProperty("gestureProp.An_Integer", "42");
+ idcProps.addProperty("gestureProp.A_Boolean", "1");
+ idcProps.addProperty("gestureProp.A_Real", "3.14159");
+
+ mProvider.loadPropertiesFromIdcFile(idcProps);
+ EXPECT_THAT(mProvider.getProperty("An Integer").getIntValues(), ElementsAre(42));
+ EXPECT_THAT(mProvider.getProperty("A Boolean").getBoolValues(), ElementsAre(true));
+ EXPECT_NEAR(mProvider.getProperty("A Real").getRealValues()[0], 3.14159, EPSILON);
+}
+
+TEST_F(PropertyProviderIdcLoadingTest, InvalidPropsIgnored) {
+ int intArrayData[2];
+ int initialInts[2] = {0, 1};
+ gesturePropProvider.create_int_fn(&mProvider, "Two Integers", intArrayData, 2, initialInts);
+
+ PropertyMap idcProps;
+ // Wrong type
+ idcProps.addProperty("gestureProp.An_Integer", "37.25");
+ // Wrong size
+ idcProps.addProperty("gestureProp.Two_Integers", "42");
+ // Doesn't exist
+ idcProps.addProperty("gestureProp.Some_Nonexistent_Property", "1");
+ // A valid assignment that should still be applied despite the others being invalid
+ idcProps.addProperty("gestureProp.A_Real", "3.14159");
+
+ mProvider.loadPropertiesFromIdcFile(idcProps);
+ EXPECT_THAT(mProvider.getProperty("An Integer").getIntValues(), ElementsAre(0));
+ EXPECT_THAT(mProvider.getProperty("Two Integers").getIntValues(), ElementsAre(0, 1));
+ EXPECT_FALSE(mProvider.hasProperty("Some Nonexistent Property"));
+ EXPECT_NEAR(mProvider.getProperty("A Real").getRealValues()[0], 3.14159, EPSILON);
+}
+
+TEST_F(PropertyProviderIdcLoadingTest, FunkyName) {
+ int data;
+ int initialData = 0;
+ gesturePropProvider.create_int_fn(&mProvider, " I lOvE sNAKes ", &data, 1, &initialData);
+
+ PropertyMap idcProps;
+ idcProps.addProperty("gestureProp.__I_lOvE_sNAKes_", "42");
+
+ mProvider.loadPropertiesFromIdcFile(idcProps);
+ EXPECT_THAT(mProvider.getProperty(" I lOvE sNAKes ").getIntValues(), ElementsAre(42));
+}
+
} // namespace android
diff --git a/services/inputflinger/tests/TestConstants.h b/services/inputflinger/tests/TestConstants.h
index 27881f6..ad48b0f 100644
--- a/services/inputflinger/tests/TestConstants.h
+++ b/services/inputflinger/tests/TestConstants.h
@@ -16,6 +16,10 @@
#pragma once
+#include <chrono>
+
+#include <utils/Timers.h>
+
namespace android {
using std::chrono_literals::operator""ms;
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/CursorInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp
index be85026..9a19b97 100644
--- a/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp
@@ -60,7 +60,7 @@
std::list<NotifyArgs> unused =
mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig, 0);
InputDeviceInfo info;
- mapper.populateDeviceInfo(&info);
+ mapper.populateDeviceInfo(info);
},
[&]() -> void {
int32_t type, code;
diff --git a/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp
index 8e2d677..33e7dbf 100644
--- a/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp
@@ -59,7 +59,7 @@
},
[&]() -> void {
InputDeviceInfo info;
- mapper.populateDeviceInfo(&info);
+ mapper.populateDeviceInfo(info);
},
[&]() -> void { mapper.getSources(); },
[&]() -> void {
diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h
index 546121d..2cb5cdf 100644
--- a/services/inputflinger/tests/fuzzers/MapperHelpers.h
+++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h
@@ -225,14 +225,21 @@
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/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp
index 011455b..59cb94a 100644
--- a/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp
@@ -74,7 +74,7 @@
},
[&]() -> void {
InputDeviceInfo info;
- mapper.populateDeviceInfo(&info);
+ mapper.populateDeviceInfo(info);
},
[&]() -> void { mapper.getSources(); },
[&]() -> void {
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 3cdb3d5..01db0cd 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()};
}
@@ -181,11 +182,23 @@
getCompositionDisplay()->applyDisplayBrightness(true);
}
- mPowerMode = mode;
+ if (mPowerMode) {
+ *mPowerMode = mode;
+ } else {
+ mPowerMode.emplace("PowerMode -" + to_string(getId()), mode);
+ }
getCompositionDisplay()->setCompositionEnabled(isPoweredOn());
}
+void DisplayDevice::tracePowerMode() {
+ // assign the same value for tracing
+ if (mPowerMode) {
+ const hal::PowerMode powerMode = *mPowerMode;
+ *mPowerMode = powerMode;
+ }
+}
+
void DisplayDevice::enableLayerCaching(bool enable) {
getCompositionDisplay()->setLayerCachingEnabled(enable);
}
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index d9c3e1c..51876e7 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -175,6 +175,7 @@
std::optional<hardware::graphics::composer::hal::PowerMode> getPowerMode() const;
void setPowerMode(hardware::graphics::composer::hal::PowerMode mode);
bool isPoweredOn() const;
+ void tracePowerMode();
// Enables layer caching on this DisplayDevice
void enableLayerCaching(bool enable);
@@ -276,7 +277,8 @@
static ui::Transform::RotationFlags sPrimaryDisplayRotationFlags;
// Allow nullopt as initial power mode.
- std::optional<hardware::graphics::composer::hal::PowerMode> mPowerMode;
+ using TracedPowerMode = TracedOrdinal<hardware::graphics::composer::hal::PowerMode>;
+ std::optional<TracedPowerMode> mPowerMode;
std::optional<float> mStagedBrightness;
std::optional<float> mBrightness;
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 5efa394..ce21233 100644
--- a/services/surfaceflinger/FrontEnd/LayerCreationArgs.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerCreationArgs.cpp
@@ -69,7 +69,9 @@
: LayerCreationArgs(nullptr, nullptr, /*name=*/"", /*flags=*/0, /*metadata=*/{}, id,
internalLayer) {}
-LayerCreationArgs::LayerCreationArgs(const LayerCreationArgs& args)
- : LayerCreationArgs(args.flinger, args.client, args.name, args.flags, args.metadata) {}
+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 8341e1d..011250c 100644
--- a/services/surfaceflinger/FrontEnd/LayerCreationArgs.h
+++ b/services/surfaceflinger/FrontEnd/LayerCreationArgs.h
@@ -37,13 +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(std::optional<uint32_t> id, bool internalLayer = false);
-
- LayerCreationArgs(const LayerCreationArgs&);
+ LayerCreationArgs() = default; // for tracing
android::SurfaceFlinger* flinger;
sp<android::Client> client;
diff --git a/services/surfaceflinger/FrontEnd/LayerHierarchy.h b/services/surfaceflinger/FrontEnd/LayerHierarchy.h
index 3dd89ba..b25b731 100644
--- a/services/surfaceflinger/FrontEnd/LayerHierarchy.h
+++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.h
@@ -104,6 +104,16 @@
static const TraversalPath ROOT;
};
+ struct TraversalPathHash {
+ std::size_t operator()(const LayerHierarchy::TraversalPath& key) const {
+ uint32_t hashCode = key.id * 31;
+ if (key.mirrorRootId != UNASSIGNED_LAYER_ID) {
+ hashCode += key.mirrorRootId * 31;
+ }
+ return std::hash<size_t>{}(hashCode);
+ }
+ };
+
// Helper class to add nodes to an existing traversal id and removes the
// node when it goes out of scope.
class ScopedAddToTraversalPath {
diff --git a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp
index fe42422..3706225 100644
--- a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp
@@ -71,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;
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/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
index 8a45093..2d6d8ad 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
@@ -28,9 +28,14 @@
const LayerHierarchy::TraversalPath& path)
: path(path) {
static uint32_t sUniqueSequenceId = 0;
- // Provide a unique id for clones otherwise keeping using the sequence id.
- // The seq id can still be useful for debugging if its available.
- uniqueSequence = (path.isClone()) ? sUniqueSequenceId++ : state.id;
+ // Provide a unique id for all snapshots.
+ // A front end layer can generate multiple snapshots if its mirrored.
+ // Additionally, if the layer is not reachable, we may choose to destroy
+ // and recreate the snapshot in which case the unique sequence id will
+ // change. The consumer shouldn't tie any lifetimes to this unique id but
+ // register a LayerLifecycleManager::ILifecycleListener or get a list of
+ // destroyed layers from LayerLifecycleManager.
+ uniqueSequence = sUniqueSequenceId++;
sequence = static_cast<int32_t>(state.id);
name = state.name;
textureName = state.textureName;
@@ -39,6 +44,8 @@
inputInfo.id = static_cast<int32_t>(uniqueSequence);
inputInfo.ownerUid = static_cast<int32_t>(state.ownerUid);
inputInfo.ownerPid = state.ownerPid;
+ uid = state.ownerUid;
+ pid = state.ownerPid;
changes = RequestedLayerState::Changes::Created;
mirrorRootPath = path.variant == LayerHierarchy::Variant::Mirror
? path
@@ -174,7 +181,12 @@
std::stringstream debug;
debug << "Snapshot{" << path.toString() << name << " isVisible=" << isVisible << " {"
<< getIsVisibleReason() << "} changes=" << changes.string()
- << " layerStack=" << outputFilter.layerStack.id << "}";
+ << " layerStack=" << outputFilter.layerStack.id << " geomLayerBounds={"
+ << geomLayerBounds.left << "," << geomLayerBounds.top << "," << geomLayerBounds.bottom
+ << "," << geomLayerBounds.right << "}"
+ << " geomLayerTransform={tx=" << geomLayerTransform.tx()
+ << ",ty=" << geomLayerTransform.ty() << "}"
+ << "}";
return debug.str();
}
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
index 6fb2f57..e22c279 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
@@ -93,6 +93,8 @@
int32_t frameRateSelectionPriority;
LayerHierarchy::TraversalPath mirrorRootPath;
bool unreachable = true;
+ uid_t uid;
+ pid_t pid;
ChildState childState;
static bool isOpaqueFormat(PixelFormat format);
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index a16de1b..2fc9682 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -21,6 +21,7 @@
#include "LayerSnapshotBuilder.h"
#include <gui/TraceUtils.h>
+#include <ui/FloatRect.h>
#include <numeric>
#include "DisplayHardware/HWC2.h"
#include "DisplayHardware/Hal.h"
@@ -101,43 +102,52 @@
}
/**
+ * Returns the bounds used to fill the input frame and the touchable region.
+ *
* Similar to getInputTransform, we need to update the bounds to include the transform.
* This is because bounds don't include the buffer transform, where the input assumes
* that's already included.
*/
-Rect getInputBounds(const LayerSnapshot& snapshot) {
- if (!snapshot.hasBufferOrSidebandStream()) {
- return snapshot.croppedBufferSize;
+std::pair<FloatRect, bool> getInputBounds(const LayerSnapshot& snapshot, bool fillParentBounds) {
+ FloatRect inputBounds = snapshot.croppedBufferSize.toFloatRect();
+ if (snapshot.hasBufferOrSidebandStream() && snapshot.croppedBufferSize.isValid() &&
+ snapshot.localTransform.getType() != ui::Transform::IDENTITY) {
+ inputBounds = snapshot.localTransform.transform(inputBounds);
}
- if (snapshot.localTransform.getType() == ui::Transform::IDENTITY ||
- !snapshot.croppedBufferSize.isValid()) {
- return snapshot.croppedBufferSize;
+ bool inputBoundsValid = snapshot.croppedBufferSize.isValid();
+ if (!inputBoundsValid) {
+ /**
+ * Input bounds are based on the layer crop or buffer size. But if we are using
+ * the layer bounds as the input bounds (replaceTouchableRegionWithCrop flag) then
+ * we can use the parent bounds as the input bounds if the layer does not have buffer
+ * or a crop. We want to unify this logic but because of compat reasons we cannot always
+ * use the parent bounds. A layer without a buffer can get input. So when a window is
+ * initially added, its touchable region can fill its parent layer bounds and that can
+ * have negative consequences.
+ */
+ inputBounds = fillParentBounds ? snapshot.geomLayerBounds : FloatRect{};
}
- return snapshot.localTransform.transform(snapshot.croppedBufferSize);
+
+ // Clamp surface inset to the input bounds.
+ const float inset = static_cast<float>(snapshot.inputInfo.surfaceInset);
+ const float xSurfaceInset = std::clamp(inset, 0.f, inputBounds.getWidth() / 2.f);
+ const float ySurfaceInset = std::clamp(inset, 0.f, inputBounds.getHeight() / 2.f);
+
+ // Apply the insets to the input bounds.
+ inputBounds.left += xSurfaceInset;
+ inputBounds.top += ySurfaceInset;
+ inputBounds.right -= xSurfaceInset;
+ inputBounds.bottom -= ySurfaceInset;
+ return {inputBounds, inputBoundsValid};
}
-void fillInputFrameInfo(gui::WindowInfo& info, const ui::Transform& screenToDisplay,
- const LayerSnapshot& snapshot) {
- Rect tmpBounds = getInputBounds(snapshot);
- if (!tmpBounds.isValid()) {
- info.touchableRegion.clear();
- // A layer could have invalid input bounds and still expect to receive touch input if it has
- // replaceTouchableRegionWithCrop. For that case, the input transform needs to be calculated
- // correctly to determine the coordinate space for input events. Use an empty rect so that
- // the layer will receive input in its own layer space.
- tmpBounds = Rect::EMPTY_RECT;
- }
-
+Rect getInputBoundsInDisplaySpace(const LayerSnapshot& snapshot, const FloatRect& insetBounds,
+ const ui::Transform& screenToDisplay) {
// InputDispatcher works in the display device's coordinate space. Here, we calculate the
// frame and transform used for the layer, which determines the bounds and the coordinate space
// within which the layer will receive input.
- //
- // The coordinate space within which each of the bounds are specified is explicitly documented
- // in the variable name. For example "inputBoundsInLayer" is specified in layer space. A
- // Transform converts one coordinate space to another, which is apparent in its naming. For
- // example, "layerToDisplay" transforms layer space to display space.
- //
+
// Coordinate space definitions:
// - display: The display device's coordinate space. Correlates to pixels on the display.
// - screen: The post-rotation coordinate space for the display, a.k.a. logical display space.
@@ -145,37 +155,34 @@
// - input: The coordinate space in which this layer will receive input events. This could be
// different than layer space if a surfaceInset is used, which changes the origin
// of the input space.
- const FloatRect inputBoundsInLayer = tmpBounds.toFloatRect();
-
- // Clamp surface inset to the input bounds.
- const auto surfaceInset = static_cast<float>(info.surfaceInset);
- const float xSurfaceInset =
- std::max(0.f, std::min(surfaceInset, inputBoundsInLayer.getWidth() / 2.f));
- const float ySurfaceInset =
- std::max(0.f, std::min(surfaceInset, inputBoundsInLayer.getHeight() / 2.f));
-
- // Apply the insets to the input bounds.
- const FloatRect insetBoundsInLayer(inputBoundsInLayer.left + xSurfaceInset,
- inputBoundsInLayer.top + ySurfaceInset,
- inputBoundsInLayer.right - xSurfaceInset,
- inputBoundsInLayer.bottom - ySurfaceInset);
// Crop the input bounds to ensure it is within the parent's bounds.
- const FloatRect croppedInsetBoundsInLayer =
- snapshot.geomLayerBounds.intersect(insetBoundsInLayer);
+ const FloatRect croppedInsetBoundsInLayer = snapshot.geomLayerBounds.intersect(insetBounds);
const ui::Transform layerToScreen = getInputTransform(snapshot);
const ui::Transform layerToDisplay = screenToDisplay * layerToScreen;
- const Rect roundedFrameInDisplay{layerToDisplay.transform(croppedInsetBoundsInLayer)};
+ return Rect{layerToDisplay.transform(croppedInsetBoundsInLayer)};
+}
+
+void fillInputFrameInfo(gui::WindowInfo& info, const ui::Transform& screenToDisplay,
+ const LayerSnapshot& snapshot) {
+ auto [inputBounds, inputBoundsValid] = getInputBounds(snapshot, /*fillParentBounds=*/false);
+ if (!inputBoundsValid) {
+ info.touchableRegion.clear();
+ }
+
+ const Rect roundedFrameInDisplay =
+ getInputBoundsInDisplaySpace(snapshot, inputBounds, screenToDisplay);
info.frameLeft = roundedFrameInDisplay.left;
info.frameTop = roundedFrameInDisplay.top;
info.frameRight = roundedFrameInDisplay.right;
info.frameBottom = roundedFrameInDisplay.bottom;
ui::Transform inputToLayer;
- inputToLayer.set(insetBoundsInLayer.left, insetBoundsInLayer.top);
- const ui::Transform inputToDisplay = layerToDisplay * inputToLayer;
+ inputToLayer.set(inputBounds.left, inputBounds.top);
+ const ui::Transform layerToScreen = getInputTransform(snapshot);
+ const ui::Transform inputToDisplay = screenToDisplay * layerToScreen * inputToLayer;
// InputDispatcher expects a display-to-input transform.
info.transform = inputToDisplay.inverse();
@@ -1008,12 +1015,26 @@
auto cropLayerSnapshot = getSnapshot(requested.touchCropId);
if (snapshot.inputInfo.replaceTouchableRegionWithCrop) {
- const Rect bounds(cropLayerSnapshot ? cropLayerSnapshot->transformedBounds
- : snapshot.transformedBounds);
- snapshot.inputInfo.touchableRegion = Region(displayInfo.transform.transform(bounds));
+ Rect inputBoundsInDisplaySpace;
+ if (!cropLayerSnapshot) {
+ FloatRect inputBounds = getInputBounds(snapshot, /*fillParentBounds=*/true).first;
+ inputBoundsInDisplaySpace =
+ getInputBoundsInDisplaySpace(snapshot, inputBounds, displayInfo.transform);
+ } else {
+ FloatRect inputBounds =
+ getInputBounds(*cropLayerSnapshot, /*fillParentBounds=*/true).first;
+ inputBoundsInDisplaySpace =
+ getInputBoundsInDisplaySpace(*cropLayerSnapshot, inputBounds,
+ displayInfo.transform);
+ }
+ snapshot.inputInfo.touchableRegion = Region(inputBoundsInDisplaySpace);
} else if (cropLayerSnapshot) {
+ FloatRect inputBounds = getInputBounds(*cropLayerSnapshot, /*fillParentBounds=*/true).first;
+ Rect inputBoundsInDisplaySpace =
+ getInputBoundsInDisplaySpace(*cropLayerSnapshot, inputBounds,
+ displayInfo.transform);
snapshot.inputInfo.touchableRegion = snapshot.inputInfo.touchableRegion.intersect(
- displayInfo.transform.transform(Rect{cropLayerSnapshot->transformedBounds}));
+ displayInfo.transform.transform(inputBoundsInDisplaySpace));
}
// Inherit the trusted state from the parent hierarchy, but don't clobber the trusted state
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
index 3997a0a..7b1ff27 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
@@ -68,6 +68,7 @@
void update(const Args&);
std::vector<std::unique_ptr<LayerSnapshot>>& getSnapshots();
LayerSnapshot* getSnapshot(uint32_t layerId) const;
+ LayerSnapshot* getSnapshot(const LayerHierarchy::TraversalPath& id) const;
typedef std::function<void(const LayerSnapshot& snapshot)> ConstVisitor;
@@ -86,7 +87,6 @@
private:
friend class LayerSnapshotTest;
- LayerSnapshot* getSnapshot(const LayerHierarchy::TraversalPath& id) const;
static LayerSnapshot getRootSnapshot();
// return true if we were able to successfully update the snapshots via
@@ -120,16 +120,8 @@
void updateChildState(LayerSnapshot& snapshot, const LayerSnapshot& childSnapshot,
const Args& args);
- struct TraversalPathHash {
- std::size_t operator()(const LayerHierarchy::TraversalPath& key) const {
- uint32_t hashCode = key.id * 31;
- if (key.mirrorRootId != UNASSIGNED_LAYER_ID) {
- hashCode += key.mirrorRootId * 31;
- }
- return std::hash<size_t>{}(hashCode);
- }
- };
- std::unordered_map<LayerHierarchy::TraversalPath, LayerSnapshot*, TraversalPathHash>
+ std::unordered_map<LayerHierarchy::TraversalPath, LayerSnapshot*,
+ LayerHierarchy::TraversalPathHash>
mIdToSnapshot;
std::vector<std::unique_ptr<LayerSnapshot>> mSnapshots;
LayerSnapshot mRootSnapshot;
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/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 0f2af2f..64f5c28 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -52,8 +52,11 @@
#include <system/graphics-base-v1.0.h>
#include <ui/DataspaceUtils.h>
#include <ui/DebugUtils.h>
+#include <ui/FloatRect.h>
#include <ui/GraphicBuffer.h>
#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <ui/Transform.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <utils/NativeHandle.h>
@@ -335,6 +338,7 @@
return nullptr;
}
mGetHandleCalled = true;
+ mHandleAlive = true;
return sp<LayerHandle>::make(mFlinger, sp<Layer>::fromExisting(this));
}
@@ -1649,9 +1653,9 @@
mFlinger->mFrameTracer->onDestroy(layerId);
}
-size_t Layer::getChildrenCount() const {
+size_t Layer::getDescendantCount() const {
size_t count = 0;
- for (const sp<Layer>& child : mCurrentChildren) {
+ for (const sp<Layer>& child : mDrawingChildren) {
count += 1 + child->getChildrenCount();
}
return count;
@@ -1898,6 +1902,12 @@
}
}
+void Layer::traverseChildren(const LayerVector::Visitor& visitor) {
+ for (const sp<Layer>& child : mDrawingChildren) {
+ visitor(child.get());
+ }
+}
+
LayerVector Layer::makeChildrenTraversalList(LayerVector::StateSet stateSet,
const std::vector<Layer*>& layersInTree) {
LOG_ALWAYS_FATAL_IF(stateSet == LayerVector::StateSet::Invalid,
@@ -2297,62 +2307,21 @@
}
void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& screenToDisplay) {
- Rect tmpBounds = getInputBounds();
- if (!tmpBounds.isValid()) {
+ auto [inputBounds, inputBoundsValid] = getInputBounds(/*fillParentBounds=*/false);
+ if (!inputBoundsValid) {
info.touchableRegion.clear();
- // A layer could have invalid input bounds and still expect to receive touch input if it has
- // replaceTouchableRegionWithCrop. For that case, the input transform needs to be calculated
- // correctly to determine the coordinate space for input events. Use an empty rect so that
- // the layer will receive input in its own layer space.
- tmpBounds = Rect::EMPTY_RECT;
}
- // InputDispatcher works in the display device's coordinate space. Here, we calculate the
- // frame and transform used for the layer, which determines the bounds and the coordinate space
- // within which the layer will receive input.
- //
- // The coordinate space within which each of the bounds are specified is explicitly documented
- // in the variable name. For example "inputBoundsInLayer" is specified in layer space. A
- // Transform converts one coordinate space to another, which is apparent in its naming. For
- // example, "layerToDisplay" transforms layer space to display space.
- //
- // Coordinate space definitions:
- // - display: The display device's coordinate space. Correlates to pixels on the display.
- // - screen: The post-rotation coordinate space for the display, a.k.a. logical display space.
- // - layer: The coordinate space of this layer.
- // - input: The coordinate space in which this layer will receive input events. This could be
- // different than layer space if a surfaceInset is used, which changes the origin
- // of the input space.
- const FloatRect inputBoundsInLayer = tmpBounds.toFloatRect();
-
- // Clamp surface inset to the input bounds.
- const auto surfaceInset = static_cast<float>(info.surfaceInset);
- const float xSurfaceInset =
- std::max(0.f, std::min(surfaceInset, inputBoundsInLayer.getWidth() / 2.f));
- const float ySurfaceInset =
- std::max(0.f, std::min(surfaceInset, inputBoundsInLayer.getHeight() / 2.f));
-
- // Apply the insets to the input bounds.
- const FloatRect insetBoundsInLayer(inputBoundsInLayer.left + xSurfaceInset,
- inputBoundsInLayer.top + ySurfaceInset,
- inputBoundsInLayer.right - xSurfaceInset,
- inputBoundsInLayer.bottom - ySurfaceInset);
-
- // Crop the input bounds to ensure it is within the parent's bounds.
- const FloatRect croppedInsetBoundsInLayer = mBounds.intersect(insetBoundsInLayer);
-
- const ui::Transform layerToScreen = getInputTransform();
- const ui::Transform layerToDisplay = screenToDisplay * layerToScreen;
-
- const Rect roundedFrameInDisplay{layerToDisplay.transform(croppedInsetBoundsInLayer)};
+ const Rect roundedFrameInDisplay = getInputBoundsInDisplaySpace(inputBounds, screenToDisplay);
info.frameLeft = roundedFrameInDisplay.left;
info.frameTop = roundedFrameInDisplay.top;
info.frameRight = roundedFrameInDisplay.right;
info.frameBottom = roundedFrameInDisplay.bottom;
ui::Transform inputToLayer;
- inputToLayer.set(insetBoundsInLayer.left, insetBoundsInLayer.top);
- const ui::Transform inputToDisplay = layerToDisplay * inputToLayer;
+ inputToLayer.set(inputBounds.left, inputBounds.top);
+ const ui::Transform layerToScreen = getInputTransform();
+ const ui::Transform inputToDisplay = screenToDisplay * layerToScreen * inputToLayer;
// InputDispatcher expects a display-to-input transform.
info.transform = inputToDisplay.inverse();
@@ -2485,13 +2454,23 @@
info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT;
}
- auto cropLayer = mDrawingState.touchableRegionCrop.promote();
+ sp<Layer> cropLayer = mDrawingState.touchableRegionCrop.promote();
if (info.replaceTouchableRegionWithCrop) {
- const Rect bounds(cropLayer ? cropLayer->mScreenBounds : mScreenBounds);
- info.touchableRegion = Region(displayTransform.transform(bounds));
+ Rect inputBoundsInDisplaySpace;
+ if (!cropLayer) {
+ FloatRect inputBounds = getInputBounds(/*fillParentBounds=*/true).first;
+ inputBoundsInDisplaySpace = getInputBoundsInDisplaySpace(inputBounds, displayTransform);
+ } else {
+ FloatRect inputBounds = cropLayer->getInputBounds(/*fillParentBounds=*/true).first;
+ inputBoundsInDisplaySpace =
+ cropLayer->getInputBoundsInDisplaySpace(inputBounds, displayTransform);
+ }
+ info.touchableRegion = Region(inputBoundsInDisplaySpace);
} else if (cropLayer != nullptr) {
- info.touchableRegion = info.touchableRegion.intersect(
- displayTransform.transform(Rect{cropLayer->mScreenBounds}));
+ FloatRect inputBounds = cropLayer->getInputBounds(/*fillParentBounds=*/true).first;
+ Rect inputBoundsInDisplaySpace =
+ cropLayer->getInputBoundsInDisplaySpace(inputBounds, displayTransform);
+ info.touchableRegion = info.touchableRegion.intersect(inputBoundsInDisplaySpace);
}
// Inherit the trusted state from the parent hierarchy, but don't clobber the trusted state
@@ -2513,6 +2492,27 @@
return info;
}
+Rect Layer::getInputBoundsInDisplaySpace(const FloatRect& inputBounds,
+ const ui::Transform& screenToDisplay) {
+ // InputDispatcher works in the display device's coordinate space. Here, we calculate the
+ // frame and transform used for the layer, which determines the bounds and the coordinate space
+ // within which the layer will receive input.
+
+ // Coordinate space definitions:
+ // - display: The display device's coordinate space. Correlates to pixels on the display.
+ // - screen: The post-rotation coordinate space for the display, a.k.a. logical display space.
+ // - layer: The coordinate space of this layer.
+ // - input: The coordinate space in which this layer will receive input events. This could be
+ // different than layer space if a surfaceInset is used, which changes the origin
+ // of the input space.
+
+ // Crop the input bounds to ensure it is within the parent's bounds.
+ const FloatRect croppedInputBounds = mBounds.intersect(inputBounds);
+ const ui::Transform layerToScreen = getInputTransform();
+ const ui::Transform layerToDisplay = screenToDisplay * layerToScreen;
+ return Rect{layerToDisplay.transform(croppedInputBounds)};
+}
+
sp<Layer> Layer::getClonedRoot() {
if (mClonedChild != nullptr) {
return sp<Layer>::fromExisting(this);
@@ -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);
@@ -3461,20 +3462,46 @@
}
/**
+ * Returns the bounds used to fill the input frame and the touchable region.
+ *
* Similar to getInputTransform, we need to update the bounds to include the transform.
* This is because bounds don't include the buffer transform, where the input assumes
* that's already included.
*/
-Rect Layer::getInputBounds() const {
- if (!hasBufferOrSidebandStream()) {
- return getCroppedBufferSize(getDrawingState());
+std::pair<FloatRect, bool> Layer::getInputBounds(bool fillParentBounds) const {
+ Rect croppedBufferSize = getCroppedBufferSize(getDrawingState());
+ FloatRect inputBounds = croppedBufferSize.toFloatRect();
+ if (hasBufferOrSidebandStream() && croppedBufferSize.isValid() &&
+ mDrawingState.transform.getType() != ui::Transform::IDENTITY) {
+ inputBounds = mDrawingState.transform.transform(inputBounds);
}
- Rect bufferBounds = getCroppedBufferSize(getDrawingState());
- if (mDrawingState.transform.getType() == ui::Transform::IDENTITY || !bufferBounds.isValid()) {
- return bufferBounds;
+ bool inputBoundsValid = croppedBufferSize.isValid();
+ if (!inputBoundsValid) {
+ /**
+ * Input bounds are based on the layer crop or buffer size. But if we are using
+ * the layer bounds as the input bounds (replaceTouchableRegionWithCrop flag) then
+ * we can use the parent bounds as the input bounds if the layer does not have buffer
+ * or a crop. We want to unify this logic but because of compat reasons we cannot always
+ * use the parent bounds. A layer without a buffer can get input. So when a window is
+ * initially added, its touchable region can fill its parent layer bounds and that can
+ * have negative consequences.
+ */
+ inputBounds = fillParentBounds ? mBounds : FloatRect{};
}
- return mDrawingState.transform.transform(bufferBounds);
+
+ // Clamp surface inset to the input bounds.
+ const float inset = static_cast<float>(mDrawingState.inputInfo.surfaceInset);
+ const float xSurfaceInset = std::clamp(inset, 0.f, inputBounds.getWidth() / 2.f);
+ const float ySurfaceInset = std::clamp(inset, 0.f, inputBounds.getHeight() / 2.f);
+
+ // Apply the insets to the input bounds.
+ inputBounds.left += xSurfaceInset;
+ inputBounds.top += ySurfaceInset;
+ inputBounds.right -= xSurfaceInset;
+ inputBounds.bottom -= ySurfaceInset;
+
+ return {inputBounds, inputBoundsValid};
}
bool Layer::simpleBufferUpdate(const layer_state_t& s) const {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 2fb122c..c91da3d 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -570,6 +570,8 @@
FloatRect getBounds(const Region& activeTransparentRegion) const;
FloatRect getBounds() const;
+ Rect getInputBoundsInDisplaySpace(const FloatRect& insetBounds,
+ const ui::Transform& displayTransform);
// Compute bounds for the layer and cache the results.
void computeBounds(FloatRect parentBounds, ui::Transform parentTransform, float shadowRadius);
@@ -700,6 +702,7 @@
void traverse(LayerVector::StateSet, const LayerVector::Visitor&);
void traverseInReverseZOrder(LayerVector::StateSet, const LayerVector::Visitor&);
void traverseInZOrder(LayerVector::StateSet, const LayerVector::Visitor&);
+ void traverseChildren(const LayerVector::Visitor&);
/**
* Traverse only children in z order, ignoring relative layers that are not children of the
@@ -707,7 +710,10 @@
*/
void traverseChildrenInZOrder(LayerVector::StateSet, const LayerVector::Visitor&);
- size_t getChildrenCount() const;
+ size_t getDescendantCount() const;
+ size_t getChildrenCount() const { return mDrawingChildren.size(); }
+ bool isHandleAlive() const { return mHandleAlive; }
+ bool onHandleDestroyed() { return mHandleAlive = false; }
// ONLY CALL THIS FROM THE LAYER DTOR!
// See b/141111965. We need to add current children to offscreen layers in
@@ -848,6 +854,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 +896,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);
@@ -931,7 +938,7 @@
* "replaceTouchableRegionWithCrop" is specified. In this case, the layer will receive input
* in this layer's space, regardless of the specified crop layer.
*/
- Rect getInputBounds() const;
+ std::pair<FloatRect, bool> getInputBounds(bool fillParentBounds) const;
// constant
sp<SurfaceFlinger> mFlinger;
@@ -1191,6 +1198,7 @@
std::vector<std::pair<frontend::LayerHierarchy::TraversalPath, sp<LayerFE>>> mLayerFEs;
std::unique_ptr<frontend::LayerSnapshot> mSnapshot =
std::make_unique<frontend::LayerSnapshot>();
+ bool mHandleAlive = false;
};
std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate);
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index 55281fa..b5ae1a7 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -15,6 +15,8 @@
*/
// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#include "FrontEnd/LayerCreationArgs.h"
+#include "FrontEnd/LayerSnapshot.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wextra"
@@ -248,47 +250,88 @@
outRegion.bottom = proto.bottom();
}
-void LayerProtoHelper::writeHierarchyToProto(
- LayersProto& outLayersProto, const frontend::LayerHierarchy& root,
- const frontend::LayerSnapshotBuilder& snapshotBuilder,
- const std::unordered_map<uint32_t, sp<Layer>>& legacyLayers, uint32_t traceFlags) {
- using Variant = frontend::LayerHierarchy::Variant;
- frontend::LayerSnapshot defaultSnapshot;
-
- LayerProto* layerProto = outLayersProto.add_layers();
- const frontend::RequestedLayerState& layer = *root.getLayer();
- frontend::LayerSnapshot* snapshot = snapshotBuilder.getSnapshot(layer.id);
-
- if (!snapshot) {
- defaultSnapshot.uniqueSequence = layer.id;
- snapshot = &defaultSnapshot;
- }
- writeSnapshotToProto(layerProto, layer, *snapshot, traceFlags);
- for (const auto& [child, variant] : root.mChildren) {
- if (variant == Variant::Attached || variant == Variant::Detached) {
- layerProto->add_children(child->getLayer()->id);
- } else if (variant == Variant::Relative) {
- layerProto->add_relatives(child->getLayer()->id);
+LayersProto LayerProtoFromSnapshotGenerator::generate(const frontend::LayerHierarchy& root) {
+ mLayersProto.clear_layers();
+ std::unordered_set<uint64_t> stackIdsToSkip;
+ if ((mTraceFlags & LayerTracing::TRACE_VIRTUAL_DISPLAYS) == 0) {
+ for (const auto& [layerStack, displayInfo] : mDisplayInfos) {
+ if (displayInfo.isVirtual) {
+ stackIdsToSkip.insert(layerStack.id);
+ }
}
}
- auto parent = root.getParent();
- if (parent && parent->getLayer()) {
- layerProto->set_parent(parent->getLayer()->id);
- } else {
- layerProto->set_parent(-1);
+ frontend::LayerHierarchy::TraversalPath path = frontend::LayerHierarchy::TraversalPath::ROOT;
+ for (auto& [child, variant] : root.mChildren) {
+ if (variant != frontend::LayerHierarchy::Variant::Attached ||
+ stackIdsToSkip.find(child->getLayer()->layerStack.id) != stackIdsToSkip.end()) {
+ continue;
+ }
+ frontend::LayerHierarchy::ScopedAddToTraversalPath addChildToPath(path,
+ child->getLayer()->id,
+ variant);
+ LayerProtoFromSnapshotGenerator::writeHierarchyToProto(*child, path);
}
- auto relativeParent = root.getRelativeParent();
- if (relativeParent && relativeParent->getLayer()) {
- layerProto->set_z_order_relative_of(relativeParent->getLayer()->id);
- } else {
- layerProto->set_z_order_relative_of(-1);
+ // fill in relative and parent info
+ for (int i = 0; i < mLayersProto.layers_size(); i++) {
+ auto layerProto = mLayersProto.mutable_layers()->Mutable(i);
+ auto it = mChildToRelativeParent.find(layerProto->id());
+ if (it == mChildToRelativeParent.end()) {
+ layerProto->set_z_order_relative_of(-1);
+ } else {
+ layerProto->set_z_order_relative_of(it->second);
+ }
+ it = mChildToParent.find(layerProto->id());
+ if (it == mChildToParent.end()) {
+ layerProto->set_parent(-1);
+ } else {
+ layerProto->set_parent(it->second);
+ }
}
- if (traceFlags & LayerTracing::TRACE_COMPOSITION) {
- auto it = legacyLayers.find(layer.id);
- if (it != legacyLayers.end()) {
+ mDefaultSnapshots.clear();
+ mChildToRelativeParent.clear();
+ return std::move(mLayersProto);
+}
+
+frontend::LayerSnapshot* LayerProtoFromSnapshotGenerator::getSnapshot(
+ frontend::LayerHierarchy::TraversalPath& path, const frontend::RequestedLayerState& layer) {
+ frontend::LayerSnapshot* snapshot = mSnapshotBuilder.getSnapshot(path);
+ if (snapshot) {
+ return snapshot;
+ } else {
+ mDefaultSnapshots[path] = frontend::LayerSnapshot(layer, path);
+ return &mDefaultSnapshots[path];
+ }
+}
+
+void LayerProtoFromSnapshotGenerator::writeHierarchyToProto(
+ const frontend::LayerHierarchy& root, frontend::LayerHierarchy::TraversalPath& path) {
+ using Variant = frontend::LayerHierarchy::Variant;
+ LayerProto* layerProto = mLayersProto.add_layers();
+ const frontend::RequestedLayerState& layer = *root.getLayer();
+ frontend::LayerSnapshot* snapshot = getSnapshot(path, layer);
+ LayerProtoHelper::writeSnapshotToProto(layerProto, layer, *snapshot, mTraceFlags);
+
+ for (const auto& [child, variant] : root.mChildren) {
+ frontend::LayerHierarchy::ScopedAddToTraversalPath addChildToPath(path,
+ child->getLayer()->id,
+ variant);
+ frontend::LayerSnapshot* childSnapshot = getSnapshot(path, layer);
+ if (variant == Variant::Attached || variant == Variant::Detached ||
+ variant == Variant::Mirror) {
+ mChildToParent[childSnapshot->uniqueSequence] = snapshot->uniqueSequence;
+ layerProto->add_children(childSnapshot->uniqueSequence);
+ } else if (variant == Variant::Relative) {
+ mChildToRelativeParent[childSnapshot->uniqueSequence] = snapshot->uniqueSequence;
+ layerProto->add_relatives(childSnapshot->uniqueSequence);
+ }
+ }
+
+ if (mTraceFlags & LayerTracing::TRACE_COMPOSITION) {
+ auto it = mLegacyLayers.find(layer.id);
+ if (it != mLegacyLayers.end()) {
it->second->writeCompositionStateToProto(layerProto);
}
}
@@ -298,7 +341,10 @@
if (variant == Variant::Detached) {
continue;
}
- writeHierarchyToProto(outLayersProto, *child, snapshotBuilder, legacyLayers, traceFlags);
+ frontend::LayerHierarchy::ScopedAddToTraversalPath addChildToPath(path,
+ child->getLayer()->id,
+ variant);
+ writeHierarchyToProto(*child, path);
}
}
@@ -345,6 +391,7 @@
layerInfo->set_shadow_radius(snapshot.shadowRadius);
layerInfo->set_id(snapshot.uniqueSequence);
+ layerInfo->set_original_id(snapshot.sequence);
layerInfo->set_name(requestedState.name);
layerInfo->set_type("Layer");
@@ -394,6 +441,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..b84a49b 100644
--- a/services/surfaceflinger/LayerProtoHelper.h
+++ b/services/surfaceflinger/LayerProtoHelper.h
@@ -25,6 +25,9 @@
#include <ui/Rect.h>
#include <ui/Region.h>
#include <ui/Transform.h>
+#include <cstdint>
+#include "FrontEnd/LayerHierarchy.h"
+#include "FrontEnd/LayerSnapshot.h"
namespace android {
namespace surfaceflinger {
@@ -58,15 +61,44 @@
static void readFromProto(const ColorTransformProto& colorTransformProto, mat4& matrix);
static void writeToProto(const android::BlurRegion region, BlurRegion*);
static void readFromProto(const BlurRegion& proto, android::BlurRegion& outRegion);
- static void writeHierarchyToProto(LayersProto& layersProto,
- const frontend::LayerHierarchy& root,
- 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);
+};
+
+class LayerProtoFromSnapshotGenerator {
+public:
+ LayerProtoFromSnapshotGenerator(
+ const frontend::LayerSnapshotBuilder& snapshotBuilder,
+ const display::DisplayMap<ui::LayerStack, frontend::DisplayInfo>& displayInfos,
+ const std::unordered_map<uint32_t, sp<Layer>>& legacyLayers, uint32_t traceFlags)
+ : mSnapshotBuilder(snapshotBuilder),
+ mLegacyLayers(legacyLayers),
+ mDisplayInfos(displayInfos),
+ mTraceFlags(traceFlags) {}
+ LayersProto generate(const frontend::LayerHierarchy& root);
+
+private:
+ void writeHierarchyToProto(const frontend::LayerHierarchy& root,
+ frontend::LayerHierarchy::TraversalPath& path);
+ frontend::LayerSnapshot* getSnapshot(frontend::LayerHierarchy::TraversalPath& path,
+ const frontend::RequestedLayerState& layer);
+
+ const frontend::LayerSnapshotBuilder& mSnapshotBuilder;
+ const std::unordered_map<uint32_t, sp<Layer>>& mLegacyLayers;
+ const display::DisplayMap<ui::LayerStack, frontend::DisplayInfo>& mDisplayInfos;
+ uint32_t mTraceFlags;
+ LayersProto mLayersProto;
+ // winscope expects all the layers, so provide a snapshot even if it not currently drawing
+ std::unordered_map<frontend::LayerHierarchy::TraversalPath, frontend::LayerSnapshot,
+ frontend::LayerHierarchy::TraversalPathHash>
+ mDefaultSnapshots;
+ std::unordered_map<uint32_t /* child unique seq*/, uint32_t /* relative parent unique seq*/>
+ mChildToRelativeParent;
+ std::unordered_map<uint32_t /* child unique seq*/, uint32_t /* parent unique seq*/>
+ mChildToParent;
};
} // namespace surfaceflinger
diff --git a/services/surfaceflinger/LayerRenderArea.cpp b/services/surfaceflinger/LayerRenderArea.cpp
index 03a7f22..1b8ff28 100644
--- a/services/surfaceflinger/LayerRenderArea.cpp
+++ b/services/surfaceflinger/LayerRenderArea.cpp
@@ -39,9 +39,12 @@
LayerRenderArea::LayerRenderArea(SurfaceFlinger& flinger, sp<Layer> layer, const Rect& crop,
ui::Size reqSize, ui::Dataspace reqDataSpace, bool childrenOnly,
- bool allowSecureLayers)
+ bool allowSecureLayers, const ui::Transform& layerTransform,
+ const Rect& layerBufferSize)
: RenderArea(reqSize, CaptureFill::CLEAR, reqDataSpace, allowSecureLayers),
mLayer(std::move(layer)),
+ mLayerTransform(layerTransform),
+ mLayerBufferSize(layerBufferSize),
mCrop(crop),
mFlinger(flinger),
mChildrenOnly(childrenOnly) {}
@@ -60,7 +63,8 @@
Rect LayerRenderArea::getSourceCrop() const {
if (mCrop.isEmpty()) {
- return mLayer->getBufferSize(mLayer->getDrawingState());
+ // TODO this should probably be mBounds instead of just buffer bounds
+ return mLayerBufferSize;
} else {
return mCrop;
}
@@ -70,7 +74,7 @@
using namespace std::string_literals;
if (!mChildrenOnly) {
- mTransform = mLayer->getTransform().inverse();
+ mTransform = mLayerTransform.inverse();
}
if (mFlinger.mLayerLifecycleManagerEnabled) {
diff --git a/services/surfaceflinger/LayerRenderArea.h b/services/surfaceflinger/LayerRenderArea.h
index 322dbd1..9bb13b3 100644
--- a/services/surfaceflinger/LayerRenderArea.h
+++ b/services/surfaceflinger/LayerRenderArea.h
@@ -33,7 +33,8 @@
class LayerRenderArea : public RenderArea {
public:
LayerRenderArea(SurfaceFlinger& flinger, sp<Layer> layer, const Rect& crop, ui::Size reqSize,
- ui::Dataspace reqDataSpace, bool childrenOnly, bool allowSecureLayers);
+ ui::Dataspace reqDataSpace, bool childrenOnly, bool allowSecureLayers,
+ const ui::Transform& layerTransform, const Rect& layerBufferSize);
const ui::Transform& getTransform() const override;
bool isSecure() const override;
@@ -45,6 +46,8 @@
private:
const sp<Layer> mLayer;
+ const ui::Transform mLayerTransform;
+ const Rect mLayerBufferSize;
const Rect mCrop;
ui::Transform mTransform;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 6e33272..f18dfdc 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -402,7 +402,6 @@
}
void Scheduler::resyncAllToHardwareVsync(bool allowToEnable) {
- ATRACE_CALL();
std::scoped_lock lock(mDisplayLock);
ftl::FakeGuard guard(kMainThreadContext);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 63b7f75..5664d84 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"
@@ -2183,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;
@@ -2235,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");
@@ -2485,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) {
@@ -2529,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;
@@ -2556,6 +2563,7 @@
if (!dropFrame) {
refreshArgs.outputs.push_back(display->getCompositionDisplay());
}
+ display->tracePowerMode();
displayIds.push_back(display->getId());
}
mPowerAdvisor->setDisplays(displayIds);
@@ -2634,7 +2642,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);
@@ -2700,7 +2710,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;
@@ -3715,8 +3725,11 @@
ATRACE_NAME("BackgroundExecutor::updateInputFlinger");
if (updateWindowInfo) {
mWindowInfosListenerInvoker
- ->windowInfosChanged(windowInfos, displayInfos,
- inputWindowCommands.windowInfosReportedListeners);
+ ->windowInfosChanged(std::move(windowInfos), std::move(displayInfos),
+ std::move(
+ inputWindowCommands.windowInfosReportedListeners),
+ /* forceImmediateCall= */
+ !inputWindowCommands.focusRequests.empty());
} else {
// If there are listeners but no changes to input windows, call the listeners
// immediately.
@@ -4083,8 +4096,34 @@
ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers.load(),
MAX_LAYERS);
static_cast<void>(mScheduler->schedule([=] {
+ ALOGE("Dumping layer keeping > 20 children alive:");
+ bool leakingParentLayerFound = false;
+ mDrawingState.traverse([&](Layer* layer) {
+ if (leakingParentLayerFound) {
+ return;
+ }
+ if (layer->getChildrenCount() > 20) {
+ leakingParentLayerFound = true;
+ sp<Layer> parent = sp<Layer>::fromExisting(layer);
+ while (parent) {
+ ALOGE("Parent Layer: %s handleIsAlive: %s", parent->getName().c_str(),
+ std::to_string(parent->isHandleAlive()).c_str());
+ parent = parent->getParent();
+ }
+ // Sample up to 100 layers
+ ALOGE("Dumping random sampling of child layers total(%zu): ",
+ layer->getChildrenCount());
+ int sampleSize = (layer->getChildrenCount() / 100) + 1;
+ layer->traverseChildren([&](Layer* layer) {
+ if (rand() % sampleSize == 0) {
+ ALOGE("Child Layer: %s", layer->getName().c_str());
+ }
+ });
+ }
+ });
+
ALOGE("Dumping random sampling of on-screen layers: ");
- mDrawingState.traverse([&](Layer *layer) {
+ mDrawingState.traverse([&](Layer* layer) {
// Aim to dump about 200 layers to avoid totally trashing
// logcat. On the other hand, if there really are 4096 layers
// something has gone totally wrong its probably the most
@@ -4093,6 +4132,8 @@
ALOGE("Layer: %s", layer->getName().c_str());
}
});
+ ALOGE("Dumping random sampling of off-screen layers total(%zu): ",
+ mOffscreenLayers.size());
for (Layer* offscreenLayer : mOffscreenLayers) {
if (rand() % 20 == 13) {
ALOGE("Offscreen-layer: %s", offscreenLayer->getName().c_str());
@@ -4112,6 +4153,9 @@
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);
@@ -4135,7 +4179,6 @@
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
@@ -4297,10 +4340,6 @@
transaction.listenerCallbacks, transaction.originPid,
transaction.originUid, transaction.id);
}
-
- if (mTransactionTracing) {
- mTransactionTracing->addCommittedTransactions(transactions, vsyncId.value);
- }
return needsTraversal;
}
@@ -5142,7 +5181,7 @@
sp<Layer> mirrorLayer;
sp<Layer> mirrorFrom;
- LayerCreationArgs mirrorArgs(args);
+ LayerCreationArgs mirrorArgs = LayerCreationArgs::fromOtherArgs(args);
{
Mutex::Autolock _l(mStateLock);
mirrorFrom = LayerHandle::getLayer(mirrorFromHandle);
@@ -5162,11 +5201,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 */);
}
@@ -5193,7 +5227,7 @@
}
layerStack = display->getLayerStack();
- LayerCreationArgs mirrorArgs(args);
+ LayerCreationArgs mirrorArgs = LayerCreationArgs::fromOtherArgs(args);
mirrorArgs.flags |= ISurfaceComposerClient::eNoColorFill;
mirrorArgs.addToRoot = true;
mirrorArgs.layerStackToMirror = layerStack;
@@ -5208,11 +5242,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);
@@ -5260,12 +5289,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) {
@@ -5307,11 +5330,9 @@
Mutex::Autolock lock(mStateLock);
markLayerPendingRemovalLocked(layer);
+ layer->onHandleDestroyed();
mBufferCountTracker.remove(handle);
layer.clear();
- if (mTransactionTracing) {
- mTransactionTracing->onHandleRemoved(handle);
- }
setTransactionFlags(eTransactionFlushNeeded);
}
@@ -5562,7 +5583,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());
@@ -5801,22 +5823,15 @@
return layersProto;
}
- const frontend::LayerHierarchy& root = mLayerHierarchyBuilder.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, mLayerSnapshotBuilder,
- mLegacyLayers, traceFlags);
- }
- return layersProto;
+ return LayerProtoFromSnapshotGenerator(mLayerSnapshotBuilder, mFrontEndDisplayInfos, {},
+ traceFlags)
+ .generate(mLayerHierarchyBuilder.getHierarchy());
}
-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);
@@ -5829,6 +5844,7 @@
displayProto->mutable_transform());
displayProto->set_is_virtual(display->isVirtual());
}
+ return displays;
}
void SurfaceFlinger::dumpHwc(std::string& result) const {
@@ -6359,9 +6375,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();
}
@@ -7034,13 +7051,34 @@
bool childrenOnly = args.childrenOnly;
RenderAreaFuture renderAreaFuture = ftl::defer([=]() -> std::unique_ptr<RenderArea> {
+ ui::Transform layerTransform;
+ Rect layerBufferSize;
+ if (mLayerLifecycleManagerEnabled) {
+ frontend::LayerSnapshot* snapshot =
+ mLayerSnapshotBuilder.getSnapshot(parent->getSequence());
+ if (!snapshot) {
+ ALOGW("Couldn't find layer snapshot for %d", parent->getSequence());
+ } else {
+ layerTransform = snapshot->localTransform;
+ layerBufferSize = snapshot->bufferSize;
+ }
+ } else {
+ layerTransform = parent->getTransform();
+ layerBufferSize = parent->getBufferSize(parent->getDrawingState());
+ }
+
return std::make_unique<LayerRenderArea>(*this, parent, crop, reqSize, dataspace,
- childrenOnly, args.captureSecureLayers);
+ childrenOnly, args.captureSecureLayers,
+ layerTransform, layerBufferSize);
});
GetLayerSnapshotsFunction getLayerSnapshots;
if (mLayerLifecycleManagerEnabled) {
- FloatRect parentCrop = crop.isEmpty() ? FloatRect(0, 0, reqSize.width, reqSize.height)
- : crop.toFloatRect();
+ std::optional<FloatRect> parentCrop = std::nullopt;
+ if (args.childrenOnly) {
+ parentCrop = crop.isEmpty() ? FloatRect(0, 0, reqSize.width, reqSize.height)
+ : crop.toFloatRect();
+ }
+
getLayerSnapshots = getLayerSnapshotsForScreenshots(parent->sequence, args.uid,
std::move(excludeLayerIds),
args.childrenOnly, parentCrop);
@@ -7724,10 +7762,6 @@
if (hintDisplay) {
layer->updateTransformHint(hintDisplay->getTransformHint());
}
-
- if (mTransactionTracing) {
- mTransactionTracing->onLayerAddedToDrawingState(layer->getSequence(), vsyncId.value);
- }
}
void SurfaceFlinger::sample() {
@@ -7868,10 +7902,6 @@
sp<Layer> childMirror;
createEffectLayer(mirrorArgs, &unused, &childMirror);
childMirror->setClonedChild(layer->createClone());
- if (mTransactionTracing) {
- mTransactionTracing->onLayerAddedToDrawingState(childMirror->getSequence(),
- vsyncId.value);
- }
childMirror->reparent(mirrorDisplay.rootHandle);
}
}
@@ -7998,7 +8028,7 @@
if (layerStack && snapshot->outputFilter.layerStack != *layerStack) {
return;
}
- if (uid != CaptureArgs::UNSET_UID && snapshot->inputInfo.ownerUid != uid) {
+ if (uid != CaptureArgs::UNSET_UID && snapshot->uid != uid) {
return;
}
if (!snapshot->hasSomethingToDraw()) {
@@ -8025,7 +8055,8 @@
std::function<std::vector<std::pair<Layer*, sp<LayerFE>>>()>
SurfaceFlinger::getLayerSnapshotsForScreenshots(uint32_t rootLayerId, uint32_t uid,
std::unordered_set<uint32_t> excludeLayerIds,
- bool childrenOnly, const FloatRect& parentCrop) {
+ bool childrenOnly,
+ const std::optional<FloatRect>& parentCrop) {
return [&, rootLayerId, uid, excludeLayerIds = std::move(excludeLayerIds), childrenOnly,
parentCrop]() {
auto root = mLayerHierarchyBuilder.getPartialHierarchy(rootLayerId, childrenOnly);
@@ -8038,7 +8069,7 @@
.globalShadowSettings = mDrawingState.globalShadowSettings,
.supportsBlur = mSupportsBlur,
.forceFullDamage = mForceFullDamage,
- .parentCrop = {parentCrop},
+ .parentCrop = parentCrop,
.excludeLayerIds = std::move(excludeLayerIds),
.supportedLayerGenericMetadata =
getHwComposer().getSupportedLayerGenericMetadata(),
@@ -8056,8 +8087,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,
@@ -8074,12 +8105,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 63d54bc..74d00dd 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);
@@ -1086,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;
@@ -1240,7 +1222,7 @@
bool mLayerCachingEnabled = false;
bool mBackpressureGpuComposition = false;
- LayerTracing mLayerTracing{*this};
+ LayerTracing mLayerTracing;
bool mLayerTracingEnabled = false;
std::optional<TransactionTracing> mTransactionTracing;
@@ -1400,7 +1382,7 @@
snapshotFilterFn);
std::function<std::vector<std::pair<Layer*, sp<LayerFE>>>()> getLayerSnapshotsForScreenshots(
uint32_t rootLayerId, uint32_t uid, std::unordered_set<uint32_t> excludeLayerIds,
- bool childrenOnly, const FloatRect& parentCrop);
+ bool childrenOnly, const std::optional<FloatRect>& optionalParentCrop);
const sp<WindowInfosListenerInvoker> mWindowInfosListenerInvoker;
@@ -1422,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/TracedOrdinal.h b/services/surfaceflinger/TracedOrdinal.h
index 558b3be..1adc3a5 100644
--- a/services/surfaceflinger/TracedOrdinal.h
+++ b/services/surfaceflinger/TracedOrdinal.h
@@ -24,16 +24,24 @@
#include <cutils/compiler.h>
#include <utils/Trace.h>
-namespace std {
-template <class Rep, class Period>
-bool signbit(std::chrono::duration<Rep, Period> v) {
- return signbit(std::chrono::duration_cast<std::chrono::nanoseconds>(v).count());
-}
-} // namespace std
-
namespace android {
namespace {
+template <class Rep, class Period>
+bool signbit(std::chrono::duration<Rep, Period> v) {
+ return std::signbit(std::chrono::duration_cast<std::chrono::nanoseconds>(v).count());
+}
+
+template <typename Enum, typename std::enable_if<std::is_enum<Enum>::value>::type* = nullptr>
+bool signbit(Enum e) {
+ return std::signbit(static_cast<typename std::underlying_type<Enum>::type>(e));
+}
+
+template <typename T, typename std::enable_if<!std::is_enum<T>::value>::type* = nullptr>
+bool signbit(T t) {
+ return std::signbit(t);
+}
+
template <typename T>
int64_t to_int64(T v) {
return int64_t(v);
@@ -49,14 +57,12 @@
class TracedOrdinal {
public:
static_assert(std::is_same<bool, T>() || (std::is_signed<T>() && std::is_integral<T>()) ||
- std::is_same<std::chrono::nanoseconds, T>(),
+ std::is_same<std::chrono::nanoseconds, T>() || std::is_enum<T>(),
"Type is not supported. Please test it with systrace before adding "
"it to the list.");
TracedOrdinal(std::string name, T initialValue)
- : mName(std::move(name)),
- mHasGoneNegative(std::signbit(initialValue)),
- mData(initialValue) {
+ : mName(std::move(name)), mHasGoneNegative(signbit(initialValue)), mData(initialValue) {
trace();
}
@@ -66,7 +72,7 @@
TracedOrdinal& operator=(T other) {
mData = other;
- mHasGoneNegative = mHasGoneNegative || std::signbit(mData);
+ mHasGoneNegative = mHasGoneNegative || signbit(mData);
trace();
return *this;
}
@@ -81,7 +87,7 @@
mNameNegative = mName + "Negative";
}
- if (!std::signbit(mData)) {
+ if (!signbit(mData)) {
ATRACE_INT64(mName.c_str(), to_int64(mData));
if (mHasGoneNegative) {
ATRACE_INT64(mNameNegative.c_str(), 0);
diff --git a/services/surfaceflinger/Tracing/LayerTracing.cpp b/services/surfaceflinger/Tracing/LayerTracing.cpp
index 566d553..ecdeabe 100644
--- a/services/surfaceflinger/Tracing/LayerTracing.cpp
+++ b/services/surfaceflinger/Tracing/LayerTracing.cpp
@@ -18,6 +18,8 @@
#define LOG_TAG "LayerTracing"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <filesystem>
+
#include <SurfaceFlinger.h>
#include <android-base/stringprintf.h>
#include <log/log.h>
@@ -29,9 +31,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;
@@ -45,30 +46,39 @@
return true;
}
-bool LayerTracing::disable(std::string filename) {
+bool LayerTracing::disable(std::string filename, bool writeToFile) {
std::scoped_lock lock(mTraceLock);
if (!mEnabled) {
return false;
}
mEnabled = false;
- LayersTraceFileProto fileProto = createTraceFileProto();
- mBuffer->writeToFile(fileProto, filename);
+ if (writeToFile) {
+ LayersTraceFileProto fileProto = createTraceFileProto();
+ mBuffer->writeToFile(fileProto, filename);
+ }
mBuffer->reset();
return true;
}
+void LayerTracing::appendToStream(std::ofstream& out) {
+ std::scoped_lock lock(mTraceLock);
+ LayersTraceFileProto fileProto = createTraceFileProto();
+ mBuffer->appendToStream(fileProto, out);
+ mBuffer->reset();
+}
+
bool LayerTracing::isEnabled() const {
std::scoped_lock lock(mTraceLock);
return mEnabled;
}
-status_t LayerTracing::writeToFile() {
+status_t LayerTracing::writeToFile(std::string filename) {
std::scoped_lock lock(mTraceLock);
if (!mEnabled) {
return STATUS_OK;
}
LayersTraceFileProto fileProto = createTraceFileProto();
- return mBuffer->writeToFile(fileProto, FILE_NAME);
+ return mBuffer->writeToFile(fileProto, filename);
}
void LayerTracing::setTraceFlags(uint32_t flags) {
@@ -84,8 +94,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 +114,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 +131,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..40b0fbe 100644
--- a/services/surfaceflinger/Tracing/LayerTracing.h
+++ b/services/surfaceflinger/Tracing/LayerTracing.h
@@ -40,14 +40,16 @@
*/
class LayerTracing {
public:
- LayerTracing(SurfaceFlinger& flinger);
+ LayerTracing();
~LayerTracing();
bool enable();
- bool disable(std::string filename = FILE_NAME);
+ bool disable(std::string filename = FILE_NAME, bool writeToFile = true);
+ void appendToStream(std::ofstream& out);
bool isEnabled() const;
- status_t writeToFile();
- LayersTraceFileProto createTraceFileProto() const;
- void notify(bool visibleRegionDirty, int64_t time, int64_t vsyncId);
+ status_t writeToFile(std::string filename = FILE_NAME);
+ 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 +62,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/RingBuffer.h b/services/surfaceflinger/Tracing/RingBuffer.h
index 7e38c55..b41c65b 100644
--- a/services/surfaceflinger/Tracing/RingBuffer.h
+++ b/services/surfaceflinger/Tracing/RingBuffer.h
@@ -24,6 +24,7 @@
#include <utils/Timers.h>
#include <utils/Trace.h>
#include <chrono>
+#include <fstream>
#include <queue>
namespace android {
@@ -73,6 +74,19 @@
return NO_ERROR;
}
+ status_t appendToStream(FileProto& fileProto, std::ofstream& out) {
+ ATRACE_CALL();
+ writeToProto(fileProto);
+ std::string output;
+ if (!fileProto.SerializeToString(&output)) {
+ ALOGE("Could not serialize proto.");
+ return UNKNOWN_ERROR;
+ }
+
+ out << output;
+ return NO_ERROR;
+ }
+
std::vector<std::string> emplace(std::string&& serializedProto) {
std::vector<std::string> replacedEntries;
size_t protoSize = static_cast<size_t>(serializedProto.size());
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
index ba08cee..7642122 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
@@ -15,15 +15,41 @@
*/
#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 = 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 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 +61,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 +72,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 +143,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 +173,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 +195,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 +204,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 +276,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 +302,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 +315,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 +410,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 +442,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 +465,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 +543,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..0ea421b 100644
--- a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
+++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
@@ -14,175 +14,32 @@
* limitations under the License.
*/
+#include <ios>
+#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 +48,108 @@
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);
+ // 10MB buffer size (large enough to hold a single entry)
+ layerTracing.setBufferSize(10 * 1024 * 1024);
+ layerTracing.enable();
+ layerTracing.writeToFile(outputLayersTracePath);
+ std::ofstream out(outputLayersTracePath, std::ios::binary | std::ios::app);
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();
+
+ LayersProto layersProto = LayerProtoFromSnapshotGenerator(snapshotBuilder, displayInfos, {},
+ layerTracing.getFlags())
+ .generate(hierarchyBuilder.getHierarchy());
+ auto displayProtos = LayerProtoHelper::writeDisplayInfoToProto(displayInfos);
+ layerTracing.notify(visibleRegionsDirty, entry.elapsed_realtime_nanos(), entry.vsync_id(),
+ &layersProto, {}, &displayProtos);
+ layerTracing.appendToStream(out);
}
-
- flingerPtr->stopLayerTracing(outputLayersTracePath);
+ layerTracing.disable("", /*writeToFile=*/false);
+ out.close();
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/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
index 292083b..73a7cae 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
@@ -25,20 +25,14 @@
using gui::IWindowInfosListener;
using gui::WindowInfo;
-struct WindowInfosListenerInvoker::WindowInfosReportedListener : gui::BnWindowInfosReportedListener,
- DeathRecipient {
- explicit WindowInfosReportedListener(
- size_t callbackCount,
- const std::unordered_set<sp<gui::IWindowInfosReportedListener>,
- SpHash<gui::IWindowInfosReportedListener>>&
- windowInfosReportedListeners)
+struct WindowInfosReportedListenerInvoker : gui::BnWindowInfosReportedListener,
+ IBinder::DeathRecipient {
+ WindowInfosReportedListenerInvoker(size_t callbackCount,
+ WindowInfosReportedListenerSet windowInfosReportedListeners)
: mCallbacksPending(callbackCount),
- mWindowInfosReportedListeners(windowInfosReportedListeners) {}
+ mWindowInfosReportedListeners(std::move(windowInfosReportedListeners)) {}
binder::Status onWindowInfosReported() override {
- // TODO(b/222421815) There could potentially be callbacks that we don't need to wait for
- // before calling the WindowInfosReportedListeners coming from InputWindowCommands. Filter
- // the list of callbacks down to those from system server.
if (--mCallbacksPending == 0) {
for (const auto& listener : mWindowInfosReportedListeners) {
sp<IBinder> asBinder = IInterface::asBinder(listener);
@@ -54,9 +48,7 @@
private:
std::atomic<size_t> mCallbacksPending;
- std::unordered_set<sp<gui::IWindowInfosReportedListener>,
- SpHash<gui::IWindowInfosReportedListener>>
- mWindowInfosReportedListeners;
+ WindowInfosReportedListenerSet mWindowInfosReportedListeners;
};
void WindowInfosListenerInvoker::addWindowInfosListener(sp<IWindowInfosListener> listener) {
@@ -82,38 +74,76 @@
}
void WindowInfosListenerInvoker::windowInfosChanged(
- const std::vector<WindowInfo>& windowInfos, const std::vector<DisplayInfo>& displayInfos,
- const std::unordered_set<sp<gui::IWindowInfosReportedListener>,
- SpHash<gui::IWindowInfosReportedListener>>&
- windowInfosReportedListeners) {
- ftl::SmallVector<const sp<IWindowInfosListener>, kStaticCapacity> windowInfosListeners;
+ std::vector<WindowInfo> windowInfos, std::vector<DisplayInfo> displayInfos,
+ WindowInfosReportedListenerSet reportedListeners, bool forceImmediateCall) {
+ reportedListeners.insert(sp<WindowInfosListenerInvoker>::fromExisting(this));
+ auto callListeners = [this, windowInfos = std::move(windowInfos),
+ displayInfos = std::move(displayInfos),
+ reportedListeners = std::move(reportedListeners)]() mutable {
+ ftl::SmallVector<const sp<IWindowInfosListener>, kStaticCapacity> windowInfosListeners;
+ {
+ std::scoped_lock lock(mListenersMutex);
+ for (const auto& [_, listener] : mWindowInfosListeners) {
+ windowInfosListeners.push_back(listener);
+ }
+ }
+
+ auto reportedInvoker =
+ sp<WindowInfosReportedListenerInvoker>::make(windowInfosListeners.size(),
+ std::move(reportedListeners));
+
+ for (const auto& listener : windowInfosListeners) {
+ sp<IBinder> asBinder = IInterface::asBinder(listener);
+
+ // linkToDeath is used here to ensure that the windowInfosReportedListeners
+ // are called even if one of the windowInfosListeners dies before
+ // calling onWindowInfosReported.
+ asBinder->linkToDeath(reportedInvoker);
+
+ auto status =
+ listener->onWindowInfosChanged(windowInfos, displayInfos, reportedInvoker);
+ if (!status.isOk()) {
+ reportedInvoker->onWindowInfosReported();
+ }
+ }
+ };
+
{
- std::scoped_lock lock(mListenersMutex);
- for (const auto& [_, listener] : mWindowInfosListeners) {
- windowInfosListeners.push_back(listener);
+ std::scoped_lock lock(mMessagesMutex);
+ // If there are unacked messages and this isn't a forced call, then return immediately.
+ // If a forced window infos change doesn't happen first, the update will be sent after
+ // the WindowInfosReportedListeners are called. If a forced window infos change happens or
+ // if there are subsequent delayed messages before this update is sent, then this message
+ // will be dropped and the listeners will only be called with the latest info. This is done
+ // to reduce the amount of binder memory used.
+ if (mActiveMessageCount > 0 && !forceImmediateCall) {
+ mWindowInfosChangedDelayed = std::move(callListeners);
+ return;
}
+
+ mWindowInfosChangedDelayed = nullptr;
+ mActiveMessageCount++;
+ }
+ callListeners();
+}
+
+binder::Status WindowInfosListenerInvoker::onWindowInfosReported() {
+ std::function<void()> callListeners;
+
+ {
+ std::scoped_lock lock{mMessagesMutex};
+ mActiveMessageCount--;
+ if (!mWindowInfosChangedDelayed || mActiveMessageCount > 0) {
+ return binder::Status::ok();
+ }
+
+ mActiveMessageCount++;
+ callListeners = std::move(mWindowInfosChangedDelayed);
+ mWindowInfosChangedDelayed = nullptr;
}
- auto windowInfosReportedListener = windowInfosReportedListeners.empty()
- ? nullptr
- : sp<WindowInfosReportedListener>::make(windowInfosListeners.size(),
- windowInfosReportedListeners);
- for (const auto& listener : windowInfosListeners) {
- sp<IBinder> asBinder = IInterface::asBinder(listener);
-
- // linkToDeath is used here to ensure that the windowInfosReportedListeners
- // are called even if one of the windowInfosListeners dies before
- // calling onWindowInfosReported.
- if (windowInfosReportedListener) {
- asBinder->linkToDeath(windowInfosReportedListener);
- }
-
- auto status = listener->onWindowInfosChanged(windowInfos, displayInfos,
- windowInfosReportedListener);
- if (windowInfosReportedListener && !status.isOk()) {
- windowInfosReportedListener->onWindowInfosReported();
- }
- }
+ callListeners();
+ return binder::Status::ok();
}
} // namespace android
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h
index d60a9c4..bfe036e 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.h
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.h
@@ -23,34 +23,40 @@
#include <android/gui/IWindowInfosReportedListener.h>
#include <binder/IBinder.h>
#include <ftl/small_map.h>
+#include <gui/SpHash.h>
#include <utils/Mutex.h>
namespace android {
-class SurfaceFlinger;
+using WindowInfosReportedListenerSet =
+ std::unordered_set<sp<gui::IWindowInfosReportedListener>,
+ gui::SpHash<gui::IWindowInfosReportedListener>>;
-class WindowInfosListenerInvoker : public IBinder::DeathRecipient {
+class WindowInfosListenerInvoker : public gui::BnWindowInfosReportedListener,
+ public IBinder::DeathRecipient {
public:
void addWindowInfosListener(sp<gui::IWindowInfosListener>);
void removeWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener);
- void windowInfosChanged(const std::vector<gui::WindowInfo>&,
- const std::vector<gui::DisplayInfo>&,
- const std::unordered_set<sp<gui::IWindowInfosReportedListener>,
- SpHash<gui::IWindowInfosReportedListener>>&
- windowInfosReportedListeners);
+ void windowInfosChanged(std::vector<gui::WindowInfo>, std::vector<gui::DisplayInfo>,
+ WindowInfosReportedListenerSet windowInfosReportedListeners,
+ bool forceImmediateCall);
+
+ binder::Status onWindowInfosReported() override;
protected:
void binderDied(const wp<IBinder>& who) override;
private:
- struct WindowInfosReportedListener;
-
std::mutex mListenersMutex;
static constexpr size_t kStaticCapacity = 3;
ftl::SmallMap<wp<IBinder>, const sp<gui::IWindowInfosListener>, kStaticCapacity>
mWindowInfosListeners GUARDED_BY(mListenersMutex);
+
+ std::mutex mMessagesMutex;
+ uint32_t mActiveMessageCount GUARDED_BY(mMessagesMutex) = 0;
+ std::function<void()> mWindowInfosChangedDelayed GUARDED_BY(mMessagesMutex);
};
} // namespace android
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index 72cecc9..6074bb7 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -452,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);
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
index c088e7b..4304259 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
@@ -25,6 +25,7 @@
#include <gui/WindowInfo.h>
#include <renderengine/mock/FakeExternalTexture.h>
#include <ui/DisplayStatInfo.h>
+#include <ui/Transform.h>
#include <FuzzableDataspaces.h>
#include <surfaceflinger_fuzzers_utils.h>
@@ -42,6 +43,7 @@
void invokeEffectLayer();
LayerCreationArgs createLayerCreationArgs(TestableSurfaceFlinger* flinger, sp<Client> client);
Rect getFuzzedRect();
+ ui::Transform getFuzzedTransform();
FrameTimelineInfo getFuzzedFrameTimelineInfo();
private:
@@ -54,6 +56,12 @@
mFdp.ConsumeIntegral<int32_t>() /*bottom*/);
}
+ui::Transform LayerFuzzer::getFuzzedTransform() {
+ return ui::Transform(mFdp.ConsumeIntegral<int32_t>() /*orientation*/,
+ mFdp.ConsumeIntegral<int32_t>() /*width*/,
+ mFdp.ConsumeIntegral<int32_t>() /*height*/);
+}
+
FrameTimelineInfo LayerFuzzer::getFuzzedFrameTimelineInfo() {
FrameTimelineInfo ftInfo;
ftInfo.vsyncId = mFdp.ConsumeIntegral<int64_t>();
@@ -166,7 +174,7 @@
{mFdp.ConsumeIntegral<int32_t>(),
mFdp.ConsumeIntegral<int32_t>()} /*reqSize*/,
mFdp.PickValueInArray(kDataspaces), mFdp.ConsumeBool(),
- mFdp.ConsumeBool());
+ mFdp.ConsumeBool(), getFuzzedTransform(), getFuzzedRect());
layerArea.render([]() {} /*drawLayers*/);
if (!ownsHandle) {
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index 3598308..e9add2e 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -138,6 +138,8 @@
float requested_corner_radius = 56;
RectProto destination_frame = 57;
+
+ uint32 original_id = 58;
}
message PositionProto {
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/Android.bp b/services/surfaceflinger/tests/Android.bp
index 6d12aa7..62b539a 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -125,6 +125,9 @@
],
cpp_std: "experimental",
gnu_extensions: false,
+ data: [
+ ":SurfaceFlinger_test",
+ ],
}
subdirs = [
diff --git a/services/surfaceflinger/tests/WindowInfosListener_test.cpp b/services/surfaceflinger/tests/WindowInfosListener_test.cpp
index d71486f..f4a8f03 100644
--- a/services/surfaceflinger/tests/WindowInfosListener_test.cpp
+++ b/services/surfaceflinger/tests/WindowInfosListener_test.cpp
@@ -17,6 +17,7 @@
#include <gtest/gtest.h>
#include <gui/SurfaceComposerClient.h>
#include <private/android_filesystem_config.h>
+#include <cstdint>
#include <future>
namespace android {
@@ -65,14 +66,14 @@
}
};
-std::optional<WindowInfo> findMatchingWindowInfo(WindowInfo targetWindowInfo,
- std::vector<WindowInfo> windowInfos) {
- for (WindowInfo windowInfo : windowInfos) {
+const WindowInfo* findMatchingWindowInfo(const WindowInfo& targetWindowInfo,
+ const std::vector<WindowInfo>& windowInfos) {
+ for (const WindowInfo& windowInfo : windowInfos) {
if (windowInfo.token == targetWindowInfo.token) {
- return windowInfo;
+ return &windowInfo;
}
}
- return std::nullopt;
+ return nullptr;
}
TEST_F(WindowInfosListenerTest, WindowInfoAddedAndRemoved) {
@@ -93,14 +94,14 @@
.apply();
auto windowPresent = [&](const std::vector<WindowInfo>& windowInfos) {
- return findMatchingWindowInfo(windowInfo, windowInfos).has_value();
+ return findMatchingWindowInfo(windowInfo, windowInfos);
};
ASSERT_TRUE(waitForWindowInfosPredicate(windowPresent));
Transaction().reparent(surfaceControl, nullptr).apply();
auto windowNotPresent = [&](const std::vector<WindowInfo>& windowInfos) {
- return !findMatchingWindowInfo(windowInfo, windowInfos).has_value();
+ return !findMatchingWindowInfo(windowInfo, windowInfos);
};
ASSERT_TRUE(waitForWindowInfosPredicate(windowNotPresent));
}
@@ -132,8 +133,7 @@
};
ASSERT_TRUE(waitForWindowInfosPredicate(windowIsPresentAndTouchableRegionEmpty));
- Rect touchableRegions(0, 0, 50, 50);
- windowInfo.addTouchableRegion(Rect(0, 0, 50, 50));
+ windowInfo.addTouchableRegion({0, 0, 50, 50});
Transaction().setInputWindowInfo(surfaceControl, windowInfo).apply();
auto windowIsPresentAndTouchableRegionMatches =
@@ -142,7 +142,10 @@
if (!foundWindowInfo) {
return false;
}
- return foundWindowInfo->touchableRegion.hasSameRects(windowInfo.touchableRegion);
+
+ auto touchableRegion =
+ foundWindowInfo->transform.transform(foundWindowInfo->touchableRegion);
+ return touchableRegion.hasSameRects(windowInfo.touchableRegion);
};
ASSERT_TRUE(waitForWindowInfosPredicate(windowIsPresentAndTouchableRegionMatches));
}
diff --git a/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp b/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp
index 5f9214c..7355c35 100644
--- a/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp
+++ b/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp
@@ -20,6 +20,7 @@
#include <fstream>
#include <iostream>
#include <string>
+#include <unordered_map>
#include <LayerTraceGenerator.h>
#include <Tracing/TransactionProtoParser.h>
@@ -84,9 +85,9 @@
std::vector<std::filesystem::path> TransactionTraceTestSuite::sTransactionTraces{};
struct LayerInfo {
- int id;
+ int32_t id;
std::string name;
- int parent;
+ int32_t parent;
int z;
uint64_t curr_frame;
float x;
@@ -143,16 +144,27 @@
expectedLayers.reserve(static_cast<size_t>(expectedLastEntry.layers().layers_size()));
for (int i = 0; i < expectedLastEntry.layers().layers_size(); i++) {
auto layer = expectedLastEntry.layers().layers(i);
- expectedLayers.push_back(getLayerInfoFromProto(layer));
+ LayerInfo layerInfo = getLayerInfoFromProto(layer);
+ expectedLayers.push_back(layerInfo);
}
std::sort(expectedLayers.begin(), expectedLayers.end(), compareById);
+ std::unordered_map<int32_t /* snapshotId*/, int32_t /*layerId*/> snapshotIdToLayerId;
std::vector<LayerInfo> actualLayers;
actualLayers.reserve(static_cast<size_t>(actualLastEntry.layers().layers_size()));
for (int i = 0; i < actualLastEntry.layers().layers_size(); i++) {
auto layer = actualLastEntry.layers().layers(i);
- actualLayers.push_back(getLayerInfoFromProto(layer));
+ LayerInfo layerInfo = getLayerInfoFromProto(layer);
+ snapshotIdToLayerId[layerInfo.id] = static_cast<int32_t>(layer.original_id());
+ actualLayers.push_back(layerInfo);
}
+
+ for (auto& layer : actualLayers) {
+ layer.id = snapshotIdToLayerId[layer.id];
+ auto it = snapshotIdToLayerId.find(layer.parent);
+ layer.parent = it == snapshotIdToLayerId.end() ? -1 : it->second;
+ }
+
std::sort(actualLayers.begin(), actualLayers.end(), compareById);
size_t i = 0;
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/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/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..82aac7e 100644
--- a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
@@ -18,7 +18,13 @@
#include <gtest/gtest.h>
#include <gui/SurfaceComposerClient.h>
+#include <cstdint>
+#include "Client.h"
+#include <layerproto/LayerProtoHeader.h>
+#include "FrontEnd/LayerCreationArgs.h"
+#include "FrontEnd/Update.h"
+#include "Tracing/LayerTracing.h"
#include "Tracing/RingBuffer.h"
#include "Tracing/TransactionTracing.h"
@@ -42,14 +48,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 +64,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 +98,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 +160,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 +184,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 +253,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;
@@ -286,4 +307,24 @@
EXPECT_EQ(proto.entry(0).transactions(0).layer_changes().size(), 2);
EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(1).z(), 43);
}
+
+// Verify we can write the layers traces by entry to reduce mem pressure
+// on the system when generating large traces.
+TEST(LayerTraceTest, canStreamLayersTrace) {
+ LayersTraceFileProto inProto = LayerTracing::createTraceFileProto();
+ inProto.add_entry();
+ inProto.add_entry();
+
+ std::string output;
+ inProto.SerializeToString(&output);
+ LayersTraceFileProto inProto2 = LayerTracing::createTraceFileProto();
+ inProto2.add_entry();
+ std::string output2;
+ inProto2.SerializeToString(&output2);
+
+ LayersTraceFileProto outProto;
+ outProto.ParseFromString(output + output2);
+ // magic?
+ EXPECT_EQ(outProto.entry().size(), 3);
+}
} // namespace android