diff options
114 files changed, 4033 insertions, 1024 deletions
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc index 34ccb21c1e..1c3a4f201c 100644 --- a/cmds/atrace/atrace.rc +++ b/cmds/atrace/atrace.rc @@ -35,6 +35,8 @@ on late-init chmod 0666 /sys/kernel/tracing/events/sched/sched_pi_setprio/enable chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_process_exit/enable chmod 0666 /sys/kernel/tracing/events/sched/sched_process_exit/enable + chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_process_free/enable + chmod 0666 /sys/kernel/tracing/events/sched/sched_process_free/enable chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_waking/enable chmod 0666 /sys/kernel/tracing/events/sched/sched_waking/enable chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_wakeup_new/enable diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 32e680dfea..e97949eb1d 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -1802,8 +1802,8 @@ static Dumpstate::RunStatus dumpstate() { // Add linker configuration directory ds.AddDir(LINKERCONFIG_DIR, true); - /* Dump cgroupfs */ - ds.AddDir(CGROUPFS_DIR, true); + /* Dump frozen cgroupfs */ + dump_frozen_cgroupfs(); if (ds.dump_pool_) { WAIT_TASK_WITH_CONSENT_CHECK(DUMP_INCIDENT_REPORT_TASK, ds.dump_pool_); @@ -4169,6 +4169,63 @@ void dump_route_tables() { fclose(fp); } +void dump_frozen_cgroupfs(const char *dir, int level, + int (*dump_from_fd)(const char* title, const char* path, int fd)) { + DIR *dirp; + struct dirent *d; + char *newpath = nullptr; + + dirp = opendir(dir); + if (dirp == nullptr) { + MYLOGE("%s: %s\n", dir, strerror(errno)); + return; + } + + for (; ((d = readdir(dirp))); free(newpath), newpath = nullptr) { + if ((d->d_name[0] == '.') + && (((d->d_name[1] == '.') && (d->d_name[2] == '\0')) + || (d->d_name[1] == '\0'))) { + continue; + } + if (d->d_type == DT_DIR) { + asprintf(&newpath, "%s/%s/", dir, d->d_name); + if (!newpath) { + continue; + } + if (level == 0 && !strncmp(d->d_name, "uid_", 4)) { + dump_frozen_cgroupfs(newpath, 1, dump_from_fd); + } else if (level == 1 && !strncmp(d->d_name, "pid_", 4)) { + char *freezer = nullptr; + asprintf(&freezer, "%s/%s", newpath, "cgroup.freeze"); + if (freezer) { + FILE* fp = fopen(freezer, "r"); + if (fp != NULL) { + int frozen; + fscanf(fp, "%d", &frozen); + if (frozen > 0) { + dump_files("", newpath, skip_none, dump_from_fd); + } + fclose(fp); + } + free(freezer); + } + } + } + } + closedir(dirp); +} + +void dump_frozen_cgroupfs() { + if (!ds.IsZipping()) { + MYLOGD("Not adding cgroupfs because it's not a zipped bugreport\n"); + return; + } + MYLOGD("Adding frozen processes from %s\n", CGROUPFS_DIR); + DurationReporter duration_reporter("FROZEN CGROUPFS"); + if (PropertiesHelper::IsDryRun()) return; + dump_frozen_cgroupfs(CGROUPFS_DIR, 0, _add_file_from_fd); +} + void Dumpstate::UpdateProgress(int32_t delta_sec) { if (progress_ == nullptr) { MYLOGE("UpdateProgress: progress_ not set\n"); diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index 773e292b63..852b9a8e24 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -637,6 +637,9 @@ void do_dmesg(); /* Prints the contents of all the routing tables, both IPv4 and IPv6. */ void dump_route_tables(); +/* Dump subdirectories of cgroupfs if the corresponding process is frozen */ +void dump_frozen_cgroupfs(); + /* Play a sound via Stagefright */ void play_sound(const char *path); diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index 289c2ae2a6..2207405341 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -1131,16 +1131,15 @@ binder::Status InstalldNativeService::fixupAppData(const std::optional<std::stri } static int32_t copy_directory_recursive(const char* from, const char* to) { - char *argv[] = { - (char*) kCpPath, - (char*) "-F", /* delete any existing destination file first (--remove-destination) */ - (char*) "-p", /* preserve timestamps, ownership, and permissions */ - (char*) "-R", /* recurse into subdirectories (DEST must be a directory) */ - (char*) "-P", /* Do not follow symlinks [default] */ - (char*) "-d", /* don't dereference symlinks */ - (char*) from, - (char*) to - }; + char* argv[] = + {(char*)kCpPath, + (char*)"-F", /* delete any existing destination file first (--remove-destination) */ + (char*)"--preserve=mode,ownership,timestamps,xattr", /* preserve properties */ + (char*)"-R", /* recurse into subdirectories (DEST must be a directory) */ + (char*)"-P", /* Do not follow symlinks [default] */ + (char*)"-d", /* don't dereference symlinks */ + (char*)from, + (char*)to}; LOG(DEBUG) << "Copying " << from << " to " << to; return logwrap_fork_execvp(ARRAY_SIZE(argv), argv, nullptr, false, LOG_ALOG, false, nullptr); diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp index 6aa32b8d8e..e978e79d86 100644 --- a/cmds/installd/otapreopt.cpp +++ b/cmds/installd/otapreopt.cpp @@ -140,8 +140,8 @@ class OTAPreoptService { PrepareEnvironmentVariables(); - if (!EnsureBootImageAndDalvikCache()) { - LOG(ERROR) << "Bad boot image."; + if (!EnsureDalvikCache()) { + LOG(ERROR) << "Bad dalvik cache."; return 5; } @@ -349,8 +349,8 @@ private: } } - // Ensure that we have the right boot image and cache file structures. - bool EnsureBootImageAndDalvikCache() const { + // Ensure that we have the right cache file structures. + bool EnsureDalvikCache() const { if (parameters_.instruction_set == nullptr) { LOG(ERROR) << "Instruction set missing."; return false; @@ -376,15 +376,6 @@ private: } } - // Check whether we have a boot image. - // TODO: check that the files are correct wrt/ jars. - std::string preopted_boot_art_path = - StringPrintf("/apex/com.android.art/javalib/%s/boot.art", isa); - if (access(preopted_boot_art_path.c_str(), F_OK) != 0) { - PLOG(ERROR) << "Bad access() to " << preopted_boot_art_path; - return false; - } - return true; } diff --git a/cmds/installd/run_dex2oat.cpp b/cmds/installd/run_dex2oat.cpp index b6616841f0..51c4589440 100644 --- a/cmds/installd/run_dex2oat.cpp +++ b/cmds/installd/run_dex2oat.cpp @@ -50,10 +50,6 @@ static constexpr bool kMinidebugInfoSystemPropertyDefault = false; static constexpr const char* kMinidebugDex2oatFlag = "--generate-mini-debug-info"; static constexpr const char* kDisableCompactDexFlag = "--compact-dex-level=none"; -// Location of the JIT Zygote image. -static const char* kJitZygoteImage = - "boot.art:/nonx/boot-framework.art!/system/etc/boot-image.prof"; - std::vector<std::string> SplitBySpaces(const std::string& str) { if (str.empty()) { return {}; @@ -84,9 +80,9 @@ void RunDex2Oat::Initialize(const UniqueFile& output_oat, int target_sdk_version, bool enable_hidden_api_checks, bool generate_compact_dex, - bool use_jitzygote_image, + bool use_jitzygote, const char* compilation_reason) { - PrepareBootImageFlags(use_jitzygote_image); + PrepareBootImageFlags(use_jitzygote); PrepareInputFileFlags(output_oat, output_vdex, output_image, input_dex, input_vdex, dex_metadata, profile, swap_fd, class_loader_context, @@ -112,14 +108,14 @@ void RunDex2Oat::Initialize(const UniqueFile& output_oat, RunDex2Oat::~RunDex2Oat() {} -void RunDex2Oat::PrepareBootImageFlags(bool use_jitzygote_image) { - std::string boot_image; - if (use_jitzygote_image) { - boot_image = StringPrintf("--boot-image=%s", kJitZygoteImage); +void RunDex2Oat::PrepareBootImageFlags(bool use_jitzygote) { + if (use_jitzygote) { + // Don't pass a boot image because JIT Zygote should decide which image to use. Typically, + // it does not use any boot image on disk. + AddArg("--force-jit-zygote"); } else { - boot_image = MapPropertyToArg("dalvik.vm.boot-image", "--boot-image=%s"); + AddArg(MapPropertyToArg("dalvik.vm.boot-image", "--boot-image=%s")); } - AddArg(boot_image); } void RunDex2Oat::PrepareInputFileFlags(const UniqueFile& output_oat, diff --git a/cmds/installd/run_dex2oat.h b/cmds/installd/run_dex2oat.h index 475e12413d..559244f2b7 100644 --- a/cmds/installd/run_dex2oat.h +++ b/cmds/installd/run_dex2oat.h @@ -50,13 +50,13 @@ class RunDex2Oat { int target_sdk_version, bool enable_hidden_api_checks, bool generate_compact_dex, - bool use_jitzygote_image, + bool use_jitzygote, const char* compilation_reason); void Exec(int exit_code); protected: - void PrepareBootImageFlags(bool use_jitzygote_image); + void PrepareBootImageFlags(bool use_jitzygote); void PrepareInputFileFlags(const UniqueFile& output_oat, const UniqueFile& output_vdex, const UniqueFile& output_image, diff --git a/cmds/installd/run_dex2oat_test.cpp b/cmds/installd/run_dex2oat_test.cpp index 0a638cd51b..2a8135a037 100644 --- a/cmds/installd/run_dex2oat_test.cpp +++ b/cmds/installd/run_dex2oat_test.cpp @@ -114,7 +114,7 @@ class RunDex2OatTest : public testing::Test { int target_sdk_version = 0; bool enable_hidden_api_checks = false; bool generate_compact_dex = true; - bool use_jitzygote_image = false; + bool use_jitzygote = false; const char* compilation_reason = nullptr; }; @@ -175,6 +175,7 @@ class RunDex2OatTest : public testing::Test { default_expected_flags_["--swap-fd"] = FLAG_UNUSED; default_expected_flags_["--class-loader-context"] = FLAG_UNUSED; default_expected_flags_["--class-loader-context-fds"] = FLAG_UNUSED; + default_expected_flags_["--boot-image"] = FLAG_UNUSED; // Arch default_expected_flags_["--instruction-set"] = "=arm64"; @@ -190,6 +191,7 @@ class RunDex2OatTest : public testing::Test { default_expected_flags_["--max-image-block-size"] = FLAG_UNUSED; default_expected_flags_["--very-large-app-threshold"] = FLAG_UNUSED; default_expected_flags_["--resolve-startup-const-strings"] = FLAG_UNUSED; + default_expected_flags_["--force-jit-zygote"] = FLAG_UNUSED; // Debug default_expected_flags_["--debuggable"] = FLAG_UNUSED; @@ -256,7 +258,7 @@ class RunDex2OatTest : public testing::Test { args->target_sdk_version, args->enable_hidden_api_checks, args->generate_compact_dex, - args->use_jitzygote_image, + args->use_jitzygote, args->compilation_reason); runner.Exec(/*exit_code=*/ 0); } @@ -557,5 +559,22 @@ TEST_F(RunDex2OatTest, ExtraFlags) { VerifyExpectedFlags(); } +TEST_F(RunDex2OatTest, UseJitZygoteImage) { + auto args = RunDex2OatArgs::MakeDefaultTestArgs(); + args->use_jitzygote = true; + CallRunDex2Oat(std::move(args)); + + SetExpectedFlagUsed("--force-jit-zygote", ""); + VerifyExpectedFlags(); +} + +TEST_F(RunDex2OatTest, BootImage) { + setSystemProperty("dalvik.vm.boot-image", "foo.art:bar.art"); + CallRunDex2Oat(RunDex2OatArgs::MakeDefaultTestArgs()); + + SetExpectedFlagUsed("--boot-image", "=foo.art:bar.art"); + VerifyExpectedFlags(); +} + } // namespace installd } // namespace android diff --git a/data/etc/android.hardware.type.automotive.xml b/data/etc/android.hardware.type.automotive.xml index a9b4b0526a..113945b0c5 100644 --- a/data/etc/android.hardware.type.automotive.xml +++ b/data/etc/android.hardware.type.automotive.xml @@ -17,4 +17,6 @@ <!-- These features determine that the device running android is a car. --> <permissions> <feature name="android.hardware.type.automotive" /> + <!-- TODO: Revert this after enabling work profiles refer b/170332519 --> + <unavailable-feature name="android.software.managed_users"/> </permissions> diff --git a/data/etc/android.software.opengles.deqp.level-2022-03-01.xml b/data/etc/android.software.opengles.deqp.level-2022-03-01.xml new file mode 100644 index 0000000000..0a118352a3 --- /dev/null +++ b/data/etc/android.software.opengles.deqp.level-2022-03-01.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- This is the standard feature indicating that the device passes OpenGL ES + dEQP tests associated with date 2022-03-01 (0x07E60301). --> +<permissions> + <feature name="android.software.opengles.deqp.level" version="132514561" /> +</permissions> diff --git a/data/etc/android.software.vulkan.deqp.level-2022-03-01.xml b/data/etc/android.software.vulkan.deqp.level-2022-03-01.xml new file mode 100644 index 0000000000..8deebc01f0 --- /dev/null +++ b/data/etc/android.software.vulkan.deqp.level-2022-03-01.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- This is the standard feature indicating that the device passes Vulkan dEQP + tests associated with date 2022-03-01 (0x07E60301). --> +<permissions> + <feature name="android.software.vulkan.deqp.level" version="132514561" /> +</permissions> diff --git a/include/input/Input.h b/include/input/Input.h index e1cacac273..ddff144954 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -382,7 +382,6 @@ struct PointerCoords { // window scale. The global scale will be applied to TOUCH/TOOL_MAJOR/MINOR // axes, however the window scaling will not. void scale(float globalScale, float windowXScale, float windowYScale); - void applyOffset(float xOffset, float yOffset); void transform(const ui::Transform& transform); @@ -572,7 +571,7 @@ public: inline float getYOffset() const { return mTransform.ty(); } - inline ui::Transform getTransform() const { return mTransform; } + inline const ui::Transform& getTransform() const { return mTransform; } int getSurfaceRotation() const; @@ -590,7 +589,7 @@ public: void setCursorPosition(float x, float y); - ui::Transform getRawTransform() const { return mRawTransform; } + inline const ui::Transform& getRawTransform() const { return mRawTransform; } static inline bool isValidCursorPosition(float x, float y) { return !isnan(x) && !isnan(y); } diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h index 451ca3c6cd..f6f8939b7a 100644 --- a/include/input/KeyCharacterMap.h +++ b/include/input/KeyCharacterMap.h @@ -84,7 +84,7 @@ public: const std::string getLoadFileName() const; - /* Combines this key character map with an overlay. */ + /* Combines this key character map with the provided overlay. */ void combine(const KeyCharacterMap& overlay); /* Gets the keyboard type. */ @@ -144,6 +144,8 @@ public: bool operator==(const KeyCharacterMap& other) const; + bool operator!=(const KeyCharacterMap& other) const; + KeyCharacterMap(const KeyCharacterMap& other); virtual ~KeyCharacterMap(); @@ -230,11 +232,12 @@ private: KeyedVector<int32_t, Key*> mKeys; KeyboardType mType; std::string mLoadFileName; + bool mLayoutOverlayApplied; KeyedVector<int32_t, int32_t> mKeysByScanCode; KeyedVector<int32_t, int32_t> mKeysByUsageCode; - KeyCharacterMap(); + KeyCharacterMap(const std::string& filename); bool getKey(int32_t keyCode, const Key** outKey) const; bool getKeyBehavior(int32_t keyCode, int32_t metaState, @@ -243,8 +246,6 @@ private: bool findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const; - static base::Result<std::shared_ptr<KeyCharacterMap>> load(Tokenizer* tokenizer, Format format); - static void addKey(Vector<KeyEvent>& outEvents, int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time); static void addMetaKeys(Vector<KeyEvent>& outEvents, @@ -264,6 +265,15 @@ private: int32_t deviceId, int32_t metaState, nsecs_t time, int32_t keyCode, int32_t keyMetaState, int32_t* currentMetaState); + + /* Clears all data stored in this key character map */ + void clear(); + + /* Loads the KeyCharacterMap provided by the tokenizer into this instance. */ + status_t load(Tokenizer* tokenizer, Format format); + + /* Reloads the data from mLoadFileName and unapplies any overlay. */ + status_t reloadBaseFromFile(); }; } // namespace android diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index f60b32e3ba..7448308ec9 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -202,7 +202,6 @@ cc_library { sanitize: { misc_undefined: ["integer"], }, - min_sdk_version: "30", tidy: true, tidy_flags: [ @@ -330,7 +329,6 @@ aidl_interface { cc_library { name: "libbinder_rpc_unstable", srcs: ["libbinder_rpc_unstable.cpp"], - defaults: ["libbinder_ndk_host_user"], shared_libs: [ "libbase", "libbinder", diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index 55d3d70bd4..13f0a4c4a5 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -352,11 +352,6 @@ bool IPCThreadState::backgroundSchedulingDisabled() return gDisableBackgroundScheduling.load(std::memory_order_relaxed); } -sp<ProcessState> IPCThreadState::process() -{ - return mProcess; -} - status_t IPCThreadState::clearLastError() { const status_t err = mLastError; diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp index 93ed50e986..ace5cd5052 100644 --- a/libs/binder/RpcServer.cpp +++ b/libs/binder/RpcServer.cpp @@ -287,8 +287,8 @@ void RpcServer::establishConnection(sp<RpcServer>&& server, base::unique_fd clie RpcConnectionHeader header; if (status == OK) { - status = client->interruptableReadFully(server->mShutdownTrigger.get(), &header, - sizeof(header), {}); + iovec iov{&header, sizeof(header)}; + status = client->interruptableReadFully(server->mShutdownTrigger.get(), &iov, 1, {}); if (status != OK) { ALOGE("Failed to read ID for client connecting to RPC server: %s", statusToString(status).c_str()); @@ -301,8 +301,9 @@ void RpcServer::establishConnection(sp<RpcServer>&& server, base::unique_fd clie if (header.sessionIdSize > 0) { if (header.sessionIdSize == kSessionIdBytes) { sessionId.resize(header.sessionIdSize); - status = client->interruptableReadFully(server->mShutdownTrigger.get(), - sessionId.data(), sessionId.size(), {}); + iovec iov{sessionId.data(), sessionId.size()}; + status = + client->interruptableReadFully(server->mShutdownTrigger.get(), &iov, 1, {}); if (status != OK) { ALOGE("Failed to read session ID for client connecting to RPC server: %s", statusToString(status).c_str()); @@ -331,8 +332,8 @@ void RpcServer::establishConnection(sp<RpcServer>&& server, base::unique_fd clie .version = protocolVersion, }; - status = client->interruptableWriteFully(server->mShutdownTrigger.get(), &response, - sizeof(response), {}); + iovec iov{&response, sizeof(response)}; + status = client->interruptableWriteFully(server->mShutdownTrigger.get(), &iov, 1, {}); if (status != OK) { ALOGE("Failed to send new session response: %s", statusToString(status).c_str()); // still need to cleanup before we can return diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp index a5a2bb1017..b84395e7cb 100644 --- a/libs/binder/RpcSession.cpp +++ b/libs/binder/RpcSession.cpp @@ -615,8 +615,9 @@ status_t RpcSession::initAndAddConnection(unique_fd fd, const std::vector<uint8_ header.options |= RPC_CONNECTION_OPTION_INCOMING; } + iovec headerIov{&header, sizeof(header)}; auto sendHeaderStatus = - server->interruptableWriteFully(mShutdownTrigger.get(), &header, sizeof(header), {}); + server->interruptableWriteFully(mShutdownTrigger.get(), &headerIov, 1, {}); if (sendHeaderStatus != OK) { ALOGE("Could not write connection header to socket: %s", statusToString(sendHeaderStatus).c_str()); @@ -624,9 +625,10 @@ status_t RpcSession::initAndAddConnection(unique_fd fd, const std::vector<uint8_ } if (sessionId.size() > 0) { + iovec sessionIov{const_cast<void*>(static_cast<const void*>(sessionId.data())), + sessionId.size()}; auto sendSessionIdStatus = - server->interruptableWriteFully(mShutdownTrigger.get(), sessionId.data(), - sessionId.size(), {}); + server->interruptableWriteFully(mShutdownTrigger.get(), &sessionIov, 1, {}); if (sendSessionIdStatus != OK) { ALOGE("Could not write session ID ('%s') to socket: %s", base::HexString(sessionId.data(), sessionId.size()).c_str(), diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp index 09b3d68626..6286c9c7bc 100644 --- a/libs/binder/RpcState.cpp +++ b/libs/binder/RpcState.cpp @@ -19,6 +19,7 @@ #include "RpcState.h" #include <android-base/hex.h> +#include <android-base/macros.h> #include <android-base/scopeguard.h> #include <binder/BpBinder.h> #include <binder/IPCThreadState.h> @@ -309,22 +310,18 @@ RpcState::CommandData::CommandData(size_t size) : mSize(size) { } status_t RpcState::rpcSend(const sp<RpcSession::RpcConnection>& connection, - const sp<RpcSession>& session, const char* what, const void* data, - size_t size, const std::function<status_t()>& altPoll) { - LOG_RPC_DETAIL("Sending %s on RpcTransport %p: %s", what, connection->rpcTransport.get(), - android::base::HexString(data, size).c_str()); - - if (size > std::numeric_limits<ssize_t>::max()) { - ALOGE("Cannot send %s at size %zu (too big)", what, size); - (void)session->shutdownAndWait(false); - return BAD_VALUE; + const sp<RpcSession>& session, const char* what, iovec* iovs, + size_t niovs, const std::function<status_t()>& altPoll) { + for (size_t i = 0; i < niovs; i++) { + LOG_RPC_DETAIL("Sending %s on RpcTransport %p: %s", what, connection->rpcTransport.get(), + android::base::HexString(iovs[i].iov_base, iovs[i].iov_len).c_str()); } if (status_t status = connection->rpcTransport->interruptableWriteFully(session->mShutdownTrigger.get(), - data, size, altPoll); + iovs, niovs, altPoll); status != OK) { - LOG_RPC_DETAIL("Failed to write %s (%zu bytes) on RpcTransport %p, error: %s", what, size, + LOG_RPC_DETAIL("Failed to write %s (%zu iovs) on RpcTransport %p, error: %s", what, niovs, connection->rpcTransport.get(), statusToString(status).c_str()); (void)session->shutdownAndWait(false); return status; @@ -334,34 +331,30 @@ status_t RpcState::rpcSend(const sp<RpcSession::RpcConnection>& connection, } status_t RpcState::rpcRec(const sp<RpcSession::RpcConnection>& connection, - const sp<RpcSession>& session, const char* what, void* data, - size_t size) { - if (size > std::numeric_limits<ssize_t>::max()) { - ALOGE("Cannot rec %s at size %zu (too big)", what, size); - (void)session->shutdownAndWait(false); - return BAD_VALUE; - } - + const sp<RpcSession>& session, const char* what, iovec* iovs, + size_t niovs) { if (status_t status = connection->rpcTransport->interruptableReadFully(session->mShutdownTrigger.get(), - data, size, {}); + iovs, niovs, {}); status != OK) { - LOG_RPC_DETAIL("Failed to read %s (%zu bytes) on RpcTransport %p, error: %s", what, size, + LOG_RPC_DETAIL("Failed to read %s (%zu iovs) on RpcTransport %p, error: %s", what, niovs, connection->rpcTransport.get(), statusToString(status).c_str()); (void)session->shutdownAndWait(false); return status; } - LOG_RPC_DETAIL("Received %s on RpcTransport %p: %s", what, connection->rpcTransport.get(), - android::base::HexString(data, size).c_str()); + for (size_t i = 0; i < niovs; i++) { + LOG_RPC_DETAIL("Received %s on RpcTransport %p: %s", what, connection->rpcTransport.get(), + android::base::HexString(iovs[i].iov_base, iovs[i].iov_len).c_str()); + } return OK; } status_t RpcState::readNewSessionResponse(const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session, uint32_t* version) { RpcNewSessionResponse response; - if (status_t status = - rpcRec(connection, session, "new session response", &response, sizeof(response)); + iovec iov{&response, sizeof(response)}; + if (status_t status = rpcRec(connection, session, "new session response", &iov, 1); status != OK) { return status; } @@ -374,14 +367,15 @@ status_t RpcState::sendConnectionInit(const sp<RpcSession::RpcConnection>& conne RpcOutgoingConnectionInit init{ .msg = RPC_CONNECTION_INIT_OKAY, }; - return rpcSend(connection, session, "connection init", &init, sizeof(init)); + iovec iov{&init, sizeof(init)}; + return rpcSend(connection, session, "connection init", &iov, 1); } status_t RpcState::readConnectionInit(const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session) { RpcOutgoingConnectionInit init; - if (status_t status = rpcRec(connection, session, "connection init", &init, sizeof(init)); - status != OK) + iovec iov{&init, sizeof(init)}; + if (status_t status = rpcRec(connection, session, "connection init", &iov, 1); status != OK) return status; static_assert(sizeof(init.msg) == sizeof(RPC_CONNECTION_INIT_OKAY)); @@ -514,17 +508,6 @@ status_t RpcState::transactAddress(const sp<RpcSession::RpcConnection>& connecti .flags = flags, .asyncNumber = asyncNumber, }; - CommandData transactionData(sizeof(RpcWireHeader) + sizeof(RpcWireTransaction) + - data.dataSize()); - if (!transactionData.valid()) { - return NO_MEMORY; - } - - memcpy(transactionData.data() + 0, &command, sizeof(RpcWireHeader)); - memcpy(transactionData.data() + sizeof(RpcWireHeader), &transaction, - sizeof(RpcWireTransaction)); - memcpy(transactionData.data() + sizeof(RpcWireHeader) + sizeof(RpcWireTransaction), data.data(), - data.dataSize()); constexpr size_t kWaitMaxUs = 1000000; constexpr size_t kWaitLogUs = 10000; @@ -550,8 +533,13 @@ status_t RpcState::transactAddress(const sp<RpcSession::RpcConnection>& connecti return drainCommands(connection, session, CommandType::CONTROL_ONLY); }; - if (status_t status = rpcSend(connection, session, "transaction", transactionData.data(), - transactionData.size(), drainRefs); + iovec iovs[]{ + {&command, sizeof(RpcWireHeader)}, + {&transaction, sizeof(RpcWireTransaction)}, + {const_cast<uint8_t*>(data.data()), data.dataSize()}, + }; + if (status_t status = + rpcSend(connection, session, "transaction", iovs, arraysize(iovs), drainRefs); status != OK) { // TODO(b/167966510): need to undo onBinderLeaving - we know the // refcount isn't successfully transferred. @@ -584,8 +572,8 @@ status_t RpcState::waitForReply(const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session, Parcel* reply) { RpcWireHeader command; while (true) { - if (status_t status = rpcRec(connection, session, "command header (for reply)", &command, - sizeof(command)); + iovec iov{&command, sizeof(command)}; + if (status_t status = rpcRec(connection, session, "command header (for reply)", &iov, 1); status != OK) return status; @@ -599,8 +587,8 @@ status_t RpcState::waitForReply(const sp<RpcSession::RpcConnection>& connection, CommandData data(command.bodySize); if (!data.valid()) return NO_MEMORY; - if (status_t status = rpcRec(connection, session, "reply body", data.data(), command.bodySize); - status != OK) + iovec iov{data.data(), command.bodySize}; + if (status_t status = rpcRec(connection, session, "reply body", &iov, 1); status != OK) return status; if (command.bodySize < sizeof(RpcWireReply)) { @@ -653,11 +641,8 @@ status_t RpcState::sendDecStrongToTarget(const sp<RpcSession::RpcConnection>& co .command = RPC_COMMAND_DEC_STRONG, .bodySize = sizeof(RpcDecStrong), }; - if (status_t status = rpcSend(connection, session, "dec ref header", &cmd, sizeof(cmd)); - status != OK) - return status; - - return rpcSend(connection, session, "dec ref body", &body, sizeof(body)); + iovec iovs[]{{&cmd, sizeof(cmd)}, {&body, sizeof(body)}}; + return rpcSend(connection, session, "dec ref", iovs, arraysize(iovs)); } status_t RpcState::getAndExecuteCommand(const sp<RpcSession::RpcConnection>& connection, @@ -665,8 +650,8 @@ status_t RpcState::getAndExecuteCommand(const sp<RpcSession::RpcConnection>& con LOG_RPC_DETAIL("getAndExecuteCommand on RpcTransport %p", connection->rpcTransport.get()); RpcWireHeader command; - if (status_t status = rpcRec(connection, session, "command header (for server)", &command, - sizeof(command)); + iovec iov{&command, sizeof(command)}; + if (status_t status = rpcRec(connection, session, "command header (for server)", &iov, 1); status != OK) return status; @@ -726,9 +711,8 @@ status_t RpcState::processTransact(const sp<RpcSession::RpcConnection>& connecti if (!transactionData.valid()) { return NO_MEMORY; } - if (status_t status = rpcRec(connection, session, "transaction body", transactionData.data(), - transactionData.size()); - status != OK) + iovec iov{transactionData.data(), transactionData.size()}; + if (status_t status = rpcRec(connection, session, "transaction body", &iov, 1); status != OK) return status; return processTransactInternal(connection, session, std::move(transactionData)); @@ -965,16 +949,12 @@ processTransactInternalTailCall: .status = replyStatus, }; - CommandData replyData(sizeof(RpcWireHeader) + sizeof(RpcWireReply) + reply.dataSize()); - if (!replyData.valid()) { - return NO_MEMORY; - } - memcpy(replyData.data() + 0, &cmdReply, sizeof(RpcWireHeader)); - memcpy(replyData.data() + sizeof(RpcWireHeader), &rpcReply, sizeof(RpcWireReply)); - memcpy(replyData.data() + sizeof(RpcWireHeader) + sizeof(RpcWireReply), reply.data(), - reply.dataSize()); - - return rpcSend(connection, session, "reply", replyData.data(), replyData.size()); + iovec iovs[]{ + {&cmdReply, sizeof(RpcWireHeader)}, + {&rpcReply, sizeof(RpcWireReply)}, + {const_cast<uint8_t*>(reply.data()), reply.dataSize()}, + }; + return rpcSend(connection, session, "reply", iovs, arraysize(iovs)); } status_t RpcState::processDecStrong(const sp<RpcSession::RpcConnection>& connection, @@ -985,9 +965,8 @@ status_t RpcState::processDecStrong(const sp<RpcSession::RpcConnection>& connect if (!commandData.valid()) { return NO_MEMORY; } - if (status_t status = - rpcRec(connection, session, "dec ref body", commandData.data(), commandData.size()); - status != OK) + iovec iov{commandData.data(), commandData.size()}; + if (status_t status = rpcRec(connection, session, "dec ref body", &iov, 1); status != OK) return status; if (command.bodySize != sizeof(RpcDecStrong)) { diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h index dba0a43060..5cad394a2f 100644 --- a/libs/binder/RpcState.h +++ b/libs/binder/RpcState.h @@ -24,6 +24,8 @@ #include <optional> #include <queue> +#include <sys/uio.h> + namespace android { struct RpcWireHeader; @@ -177,12 +179,12 @@ private: }; [[nodiscard]] status_t rpcSend(const sp<RpcSession::RpcConnection>& connection, - const sp<RpcSession>& session, const char* what, - const void* data, size_t size, + const sp<RpcSession>& session, const char* what, iovec* iovs, + size_t niovs, const std::function<status_t()>& altPoll = nullptr); [[nodiscard]] status_t rpcRec(const sp<RpcSession::RpcConnection>& connection, - const sp<RpcSession>& session, const char* what, void* data, - size_t size); + const sp<RpcSession>& session, const char* what, iovec* iovs, + size_t niovs); [[nodiscard]] status_t waitForReply(const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session, Parcel* reply); diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp index 7669518954..2182e1868e 100644 --- a/libs/binder/RpcTransportRaw.cpp +++ b/libs/binder/RpcTransportRaw.cpp @@ -43,12 +43,10 @@ public: return ret; } - template <typename Buffer, typename SendOrReceive> - status_t interruptableReadOrWrite(FdTrigger* fdTrigger, Buffer buffer, size_t size, + template <typename SendOrReceive> + status_t interruptableReadOrWrite(FdTrigger* fdTrigger, iovec* iovs, size_t niovs, SendOrReceive sendOrReceiveFun, const char* funName, int16_t event, const std::function<status_t()>& altPoll) { - const Buffer end = buffer + size; - MAYBE_WAIT_IN_FLAKE_MODE; // Since we didn't poll, we need to manually check to see if it was triggered. Otherwise, we @@ -57,26 +55,61 @@ public: return DEAD_OBJECT; } + // If iovs has one or more empty vectors at the end and + // we somehow advance past all the preceding vectors and + // pass some or all of the empty ones to sendmsg/recvmsg, + // the call will return processSize == 0. In that case + // we should be returning OK but instead return DEAD_OBJECT. + // To avoid this problem, we make sure here that the last + // vector at iovs[niovs - 1] has a non-zero length. + while (niovs > 0 && iovs[niovs - 1].iov_len == 0) { + niovs--; + } + if (niovs == 0) { + // The vectors are all empty, so we have nothing to send. + return OK; + } + bool havePolled = false; while (true) { - ssize_t processSize = TEMP_FAILURE_RETRY( - sendOrReceiveFun(mSocket.get(), buffer, end - buffer, MSG_NOSIGNAL)); + msghdr msg{ + .msg_iov = iovs, + .msg_iovlen = niovs, + }; + ssize_t processSize = + TEMP_FAILURE_RETRY(sendOrReceiveFun(mSocket.get(), &msg, MSG_NOSIGNAL)); if (processSize < 0) { int savedErrno = errno; // Still return the error on later passes, since it would expose // a problem with polling - if (havePolled || - (!havePolled && savedErrno != EAGAIN && savedErrno != EWOULDBLOCK)) { + if (havePolled || (savedErrno != EAGAIN && savedErrno != EWOULDBLOCK)) { LOG_RPC_DETAIL("RpcTransport %s(): %s", funName, strerror(savedErrno)); return -savedErrno; } } else if (processSize == 0) { return DEAD_OBJECT; } else { - buffer += processSize; - if (buffer == end) { + while (processSize > 0 && niovs > 0) { + auto& iov = iovs[0]; + if (static_cast<size_t>(processSize) < iov.iov_len) { + // Advance the base of the current iovec + iov.iov_base = reinterpret_cast<char*>(iov.iov_base) + processSize; + iov.iov_len -= processSize; + break; + } + + // The current iovec was fully written + processSize -= iov.iov_len; + iovs++; + niovs--; + } + if (niovs == 0) { + LOG_ALWAYS_FATAL_IF(processSize > 0, + "Reached the end of iovecs " + "with %zd bytes remaining", + processSize); return OK; } } @@ -95,16 +128,16 @@ public: } } - status_t interruptableWriteFully(FdTrigger* fdTrigger, const void* data, size_t size, + status_t interruptableWriteFully(FdTrigger* fdTrigger, iovec* iovs, size_t niovs, const std::function<status_t()>& altPoll) override { - return interruptableReadOrWrite(fdTrigger, reinterpret_cast<const uint8_t*>(data), size, - send, "send", POLLOUT, altPoll); + return interruptableReadOrWrite(fdTrigger, iovs, niovs, sendmsg, "sendmsg", POLLOUT, + altPoll); } - status_t interruptableReadFully(FdTrigger* fdTrigger, void* data, size_t size, + status_t interruptableReadFully(FdTrigger* fdTrigger, iovec* iovs, size_t niovs, const std::function<status_t()>& altPoll) override { - return interruptableReadOrWrite(fdTrigger, reinterpret_cast<uint8_t*>(data), size, recv, - "recv", POLLIN, altPoll); + return interruptableReadOrWrite(fdTrigger, iovs, niovs, recvmsg, "recvmsg", POLLIN, + altPoll); } private: diff --git a/libs/binder/RpcTransportTls.cpp b/libs/binder/RpcTransportTls.cpp index 7f810b17ba..c05ea1512f 100644 --- a/libs/binder/RpcTransportTls.cpp +++ b/libs/binder/RpcTransportTls.cpp @@ -275,9 +275,9 @@ public: RpcTransportTls(android::base::unique_fd socket, Ssl ssl) : mSocket(std::move(socket)), mSsl(std::move(ssl)) {} Result<size_t> peek(void* buf, size_t size) override; - status_t interruptableWriteFully(FdTrigger* fdTrigger, const void* data, size_t size, + status_t interruptableWriteFully(FdTrigger* fdTrigger, iovec* iovs, size_t niovs, const std::function<status_t()>& altPoll) override; - status_t interruptableReadFully(FdTrigger* fdTrigger, void* data, size_t size, + status_t interruptableReadFully(FdTrigger* fdTrigger, iovec* iovs, size_t niovs, const std::function<status_t()>& altPoll) override; private: @@ -303,68 +303,83 @@ Result<size_t> RpcTransportTls::peek(void* buf, size_t size) { return ret; } -status_t RpcTransportTls::interruptableWriteFully(FdTrigger* fdTrigger, const void* data, - size_t size, +status_t RpcTransportTls::interruptableWriteFully(FdTrigger* fdTrigger, iovec* iovs, size_t niovs, const std::function<status_t()>& altPoll) { - auto buffer = reinterpret_cast<const uint8_t*>(data); - const uint8_t* end = buffer + size; - MAYBE_WAIT_IN_FLAKE_MODE; // Before doing any I/O, check trigger once. This ensures the trigger is checked at least // once. The trigger is also checked via triggerablePoll() after every SSL_write(). if (fdTrigger->isTriggered()) return DEAD_OBJECT; - while (buffer < end) { - size_t todo = std::min<size_t>(end - buffer, std::numeric_limits<int>::max()); - auto [writeSize, errorQueue] = mSsl.call(SSL_write, buffer, todo); - if (writeSize > 0) { - buffer += writeSize; - errorQueue.clear(); + size_t size = 0; + for (size_t i = 0; i < niovs; i++) { + const iovec& iov = iovs[i]; + if (iov.iov_len == 0) { continue; } - // SSL_write() should never return 0 unless BIO_write were to return 0. - int sslError = mSsl.getError(writeSize); - // TODO(b/195788248): BIO should contain the FdTrigger, and send(2) / recv(2) should be - // triggerablePoll()-ed. Then additionalEvent is no longer necessary. - status_t pollStatus = errorQueue.pollForSslError(mSocket.get(), sslError, fdTrigger, - "SSL_write", POLLIN, altPoll); - if (pollStatus != OK) return pollStatus; - // Do not advance buffer. Try SSL_write() again. + size += iov.iov_len; + + auto buffer = reinterpret_cast<const uint8_t*>(iov.iov_base); + const uint8_t* end = buffer + iov.iov_len; + while (buffer < end) { + size_t todo = std::min<size_t>(end - buffer, std::numeric_limits<int>::max()); + auto [writeSize, errorQueue] = mSsl.call(SSL_write, buffer, todo); + if (writeSize > 0) { + buffer += writeSize; + errorQueue.clear(); + continue; + } + // SSL_write() should never return 0 unless BIO_write were to return 0. + int sslError = mSsl.getError(writeSize); + // TODO(b/195788248): BIO should contain the FdTrigger, and send(2) / recv(2) should be + // triggerablePoll()-ed. Then additionalEvent is no longer necessary. + status_t pollStatus = errorQueue.pollForSslError(mSocket.get(), sslError, fdTrigger, + "SSL_write", POLLIN, altPoll); + if (pollStatus != OK) return pollStatus; + // Do not advance buffer. Try SSL_write() again. + } } LOG_TLS_DETAIL("TLS: Sent %zu bytes!", size); return OK; } -status_t RpcTransportTls::interruptableReadFully(FdTrigger* fdTrigger, void* data, size_t size, +status_t RpcTransportTls::interruptableReadFully(FdTrigger* fdTrigger, iovec* iovs, size_t niovs, const std::function<status_t()>& altPoll) { - auto buffer = reinterpret_cast<uint8_t*>(data); - uint8_t* end = buffer + size; - MAYBE_WAIT_IN_FLAKE_MODE; // Before doing any I/O, check trigger once. This ensures the trigger is checked at least // once. The trigger is also checked via triggerablePoll() after every SSL_write(). if (fdTrigger->isTriggered()) return DEAD_OBJECT; - while (buffer < end) { - size_t todo = std::min<size_t>(end - buffer, std::numeric_limits<int>::max()); - auto [readSize, errorQueue] = mSsl.call(SSL_read, buffer, todo); - if (readSize > 0) { - buffer += readSize; - errorQueue.clear(); + size_t size = 0; + for (size_t i = 0; i < niovs; i++) { + const iovec& iov = iovs[i]; + if (iov.iov_len == 0) { continue; } - if (readSize == 0) { - // SSL_read() only returns 0 on EOF. - errorQueue.clear(); - return DEAD_OBJECT; + size += iov.iov_len; + + auto buffer = reinterpret_cast<uint8_t*>(iov.iov_base); + const uint8_t* end = buffer + iov.iov_len; + while (buffer < end) { + size_t todo = std::min<size_t>(end - buffer, std::numeric_limits<int>::max()); + auto [readSize, errorQueue] = mSsl.call(SSL_read, buffer, todo); + if (readSize > 0) { + buffer += readSize; + errorQueue.clear(); + continue; + } + if (readSize == 0) { + // SSL_read() only returns 0 on EOF. + errorQueue.clear(); + return DEAD_OBJECT; + } + int sslError = mSsl.getError(readSize); + status_t pollStatus = errorQueue.pollForSslError(mSocket.get(), sslError, fdTrigger, + "SSL_read", 0, altPoll); + if (pollStatus != OK) return pollStatus; + // Do not advance buffer. Try SSL_read() again. } - int sslError = mSsl.getError(readSize); - status_t pollStatus = errorQueue.pollForSslError(mSocket.get(), sslError, fdTrigger, - "SSL_read", 0, altPoll); - if (pollStatus != OK) return pollStatus; - // Do not advance buffer. Try SSL_read() again. } LOG_TLS_DETAIL("TLS: Received %zu bytes!", size); return OK; diff --git a/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl b/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl index bffab5e86b..949835b452 100644 --- a/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl +++ b/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl @@ -27,7 +27,5 @@ parcelable StagedApexInfo { @utf8InCpp String diskImagePath; long versionCode; @utf8InCpp String versionName; - boolean hasBootClassPathJars; - boolean hasDex2OatBootClassPathJars; - boolean hasSystemServerClassPathJars; + boolean hasClassPathJars; } diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h index 82bebc95f4..bf02099ffb 100644 --- a/libs/binder/include/binder/IPCThreadState.h +++ b/libs/binder/include/binder/IPCThreadState.h @@ -54,8 +54,6 @@ public: static status_t getProcessFreezeInfo(pid_t pid, uint32_t *sync_received, uint32_t *async_received); - sp<ProcessState> process(); - status_t clearLastError(); /** diff --git a/libs/binder/include/binder/RpcTransport.h b/libs/binder/include/binder/RpcTransport.h index db8b5e920e..348bfebf15 100644 --- a/libs/binder/include/binder/RpcTransport.h +++ b/libs/binder/include/binder/RpcTransport.h @@ -28,6 +28,8 @@ #include <binder/RpcCertificateFormat.h> +#include <sys/uio.h> + namespace android { class FdTrigger; @@ -44,6 +46,9 @@ public: /** * Read (or write), but allow to be interrupted by a trigger. * + * iovs - array of iovecs to perform the operation on. The elements + * of the array may be modified by this method. + * * altPoll - function to be called instead of polling, when needing to wait * to read/write data. If this returns an error, that error is returned from * this function. @@ -53,10 +58,10 @@ public: * error - interrupted (failure or trigger) */ [[nodiscard]] virtual status_t interruptableWriteFully( - FdTrigger *fdTrigger, const void *buf, size_t size, + FdTrigger *fdTrigger, iovec *iovs, size_t niovs, const std::function<status_t()> &altPoll) = 0; [[nodiscard]] virtual status_t interruptableReadFully( - FdTrigger *fdTrigger, void *buf, size_t size, + FdTrigger *fdTrigger, iovec *iovs, size_t niovs, const std::function<status_t()> &altPoll) = 0; protected: diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp index 42895740ea..77493b3882 100644 --- a/libs/binder/ndk/Android.bp +++ b/libs/binder/ndk/Android.bp @@ -32,17 +32,10 @@ license { ], } +// TODO(b/211908498): remove this cc_defaults { name: "libbinder_ndk_host_user", target: { - host: { - cflags: [ - "-D__INTRODUCED_IN(n)=", - "-D__assert(a,b,c)=do { syslog(LOG_ERR, a \": \" c); abort(); } while(false)", - // We want all the APIs to be available on the host. - "-D__ANDROID_API__=10000", - ], - }, darwin: { enabled: false, }, @@ -52,7 +45,6 @@ cc_defaults { cc_library { name: "libbinder_ndk", - defaults: ["libbinder_ndk_host_user"], host_supported: true, recovery_available: true, diff --git a/libs/binder/ndk/include_ndk/android/binder_status.h b/libs/binder/ndk/include_ndk/android/binder_status.h index 6f1fdfcd20..76c7aacb7c 100644 --- a/libs/binder/ndk/include_ndk/android/binder_status.h +++ b/libs/binder/ndk/include_ndk/android/binder_status.h @@ -32,11 +32,26 @@ __BEGIN_DECLS +#ifndef __BIONIC__ + +#ifndef __INTRODUCED_IN +#define __INTRODUCED_IN(n) +#endif + +#ifndef __assert +#define __assert(a, b, c) \ + do { \ + syslog(LOG_ERR, a ": " c); \ + abort(); \ + } while (false) +#endif + #ifndef __ANDROID_API__ -#error Android builds must be compiled against a specific API. If this is an \ - android platform host build, you must use libbinder_ndk_host_user. +#define __ANDROID_API__ 10000 #endif +#endif // __BIONIC__ + /** * Low-level status types for use in binder. This is the least preferable way to * return an error for binder services (where binder_exception_t should be used, diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp index e2fc18d859..e4df98aa4f 100644 --- a/libs/binder/rust/Android.bp +++ b/libs/binder/rust/Android.bp @@ -127,14 +127,6 @@ rust_bindgen { // Currently necessary for host builds // TODO(b/31559095): bionic on host should define this target: { - host: { - cflags: [ - "-D__INTRODUCED_IN(n)=", - "-D__assert(a,b,c)=", - // We want all the APIs to be available on the host. - "-D__ANDROID_API__=10000", - ], - }, darwin: { enabled: false, }, diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index 5a96b7835c..ca68b99e35 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -1674,8 +1674,8 @@ public: static AssertionResult defaultPostConnect(RpcTransport* serverTransport, FdTrigger* fdTrigger) { std::string message(kMessage); - auto status = serverTransport->interruptableWriteFully(fdTrigger, message.data(), - message.size(), {}); + iovec messageIov{message.data(), message.size()}; + auto status = serverTransport->interruptableWriteFully(fdTrigger, &messageIov, 1, {}); if (status != OK) return AssertionFailure() << statusToString(status); return AssertionSuccess(); } @@ -1706,9 +1706,9 @@ public: AssertionResult readMessage(const std::string& expectedMessage = kMessage) { LOG_ALWAYS_FATAL_IF(mClientTransport == nullptr, "setUpTransport not called or failed"); std::string readMessage(expectedMessage.size(), '\0'); - status_t readStatus = - mClientTransport->interruptableReadFully(mFdTrigger.get(), readMessage.data(), - readMessage.size(), {}); + iovec readMessageIov{readMessage.data(), readMessage.size()}; + status_t readStatus = mClientTransport->interruptableReadFully(mFdTrigger.get(), + &readMessageIov, 1, {}); if (readStatus != OK) { return AssertionFailure() << statusToString(readStatus); } @@ -1902,8 +1902,8 @@ TEST_P(RpcTransportTest, Trigger) { bool shouldContinueWriting = false; auto serverPostConnect = [&](RpcTransport* serverTransport, FdTrigger* fdTrigger) { std::string message(RpcTransportTestUtils::kMessage); - auto status = serverTransport->interruptableWriteFully(fdTrigger, message.data(), - message.size(), {}); + iovec messageIov{message.data(), message.size()}; + auto status = serverTransport->interruptableWriteFully(fdTrigger, &messageIov, 1, {}); if (status != OK) return AssertionFailure() << statusToString(status); { @@ -1913,7 +1913,8 @@ TEST_P(RpcTransportTest, Trigger) { } } - status = serverTransport->interruptableWriteFully(fdTrigger, msg2.data(), msg2.size(), {}); + iovec msg2Iov{msg2.data(), msg2.size()}; + status = serverTransport->interruptableWriteFully(fdTrigger, &msg2Iov, 1, {}); if (status != DEAD_OBJECT) return AssertionFailure() << "When FdTrigger is shut down, interruptableWriteFully " "should return DEAD_OBJECT, but it is " diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp index acf3f8f1f3..1446802d58 100644 --- a/libs/binder/tests/parcel_fuzzer/Android.bp +++ b/libs/binder/tests/parcel_fuzzer/Android.bp @@ -9,7 +9,6 @@ package { cc_fuzz { name: "binder_parcel_fuzzer", - defaults: ["libbinder_ndk_host_user"], host_supported: true, fuzz_config: { @@ -50,6 +49,9 @@ cc_fuzz { "libbinder", ], }, + darwin: { + enabled: false, + }, }, // This flag enables verbose output in the fuzz target, and is very useful // for debugging a failure. If you are trying to diagnose how a crash was @@ -63,7 +65,7 @@ cc_library_static { target: { darwin: { enabled: false, - } + }, }, srcs: [ "random_fd.cpp", diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index e5dcdea278..ec3587b79a 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -66,6 +66,7 @@ cc_library_static { host_supported: true, srcs: [ ":guiconstants_aidl", + ":inputconstants_aidl", "android/gui/DisplayInfo.aidl", "android/gui/FocusRequest.aidl", "android/gui/InputApplicationInfo.aidl", diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 85a4b67f34..dd966837f4 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -119,16 +119,11 @@ void BLASTBufferItemConsumer::getConnectionEvents(uint64_t frameNumber, bool* ne if (needsDisconnect != nullptr) *needsDisconnect = disconnect; } -void BLASTBufferItemConsumer::setBlastBufferQueue(BLASTBufferQueue* blastbufferqueue) { - std::scoped_lock lock(mBufferQueueMutex); - mBLASTBufferQueue = blastbufferqueue; -} - void BLASTBufferItemConsumer::onSidebandStreamChanged() { - std::scoped_lock lock(mBufferQueueMutex); - if (mBLASTBufferQueue != nullptr) { + sp<BLASTBufferQueue> bbq = mBLASTBufferQueue.promote(); + if (bbq != nullptr) { sp<NativeHandle> stream = getSidebandStream(); - mBLASTBufferQueue->setSidebandStream(stream); + bbq->setSidebandStream(stream); } } @@ -148,7 +143,7 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name) mBufferItemConsumer = new BLASTBufferItemConsumer(mConsumer, GraphicBuffer::USAGE_HW_COMPOSER | GraphicBuffer::USAGE_HW_TEXTURE, - 1, false); + 1, false, this); static int32_t id = 0; mName = name + "#" + std::to_string(id); auto consumerName = mName + "(BLAST Consumer)" + std::to_string(id); @@ -157,15 +152,13 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name) mBufferItemConsumer->setName(String8(consumerName.c_str())); mBufferItemConsumer->setFrameAvailableListener(this); mBufferItemConsumer->setBufferFreedListener(this); - mBufferItemConsumer->setBlastBufferQueue(this); ComposerService::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers); mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers); mCurrentMaxAcquiredBufferCount = mMaxAcquiredBuffers; mNumAcquired = 0; mNumFrameAvailable = 0; - BQA_LOGV("BLASTBufferQueue created width=%d height=%d format=%d mTransformHint=%d", mSize.width, - mSize.height, mFormat, mTransformHint); + BQA_LOGV("BLASTBufferQueue created"); } BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface, @@ -175,21 +168,20 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceCont } BLASTBufferQueue::~BLASTBufferQueue() { - mBufferItemConsumer->setBlastBufferQueue(nullptr); if (mPendingTransactions.empty()) { return; } BQA_LOGE("Applying pending transactions on dtor %d", static_cast<uint32_t>(mPendingTransactions.size())); SurfaceComposerClient::Transaction t; - for (auto& [targetFrameNumber, transaction] : mPendingTransactions) { - t.merge(std::move(transaction)); - } - t.apply(); + mergePendingTransactions(&t, std::numeric_limits<uint64_t>::max() /* frameNumber */); + t.setApplyToken(mApplyToken).apply(); } void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height, int32_t format, SurfaceComposerClient::Transaction* outTransaction) { + LOG_ALWAYS_FATAL_IF(surface == nullptr, "BLASTBufferQueue: mSurfaceControl must not be NULL"); + std::unique_lock _lock{mMutex}; if (mFormat != format) { mFormat = format; @@ -197,21 +189,22 @@ void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, } SurfaceComposerClient::Transaction t; - const bool setBackpressureFlag = !SurfaceControl::isSameSurface(mSurfaceControl, surface); + const bool surfaceControlChanged = !SurfaceControl::isSameSurface(mSurfaceControl, surface); + if (surfaceControlChanged && mSurfaceControl != nullptr) { + BQA_LOGD("Updating SurfaceControl without recreating BBQ"); + } bool applyTransaction = false; // Always update the native object even though they might have the same layer handle, so we can // get the updated transform hint from WM. mSurfaceControl = surface; - if (mSurfaceControl != nullptr) { - if (setBackpressureFlag) { - t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure, - layer_state_t::eEnableBackpressure); - applyTransaction = true; - } - mTransformHint = mSurfaceControl->getTransformHint(); - mBufferItemConsumer->setTransformHint(mTransformHint); + if (surfaceControlChanged) { + t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure, + layer_state_t::eEnableBackpressure); + applyTransaction = true; } + mTransformHint = mSurfaceControl->getTransformHint(); + mBufferItemConsumer->setTransformHint(mTransformHint); BQA_LOGV("update width=%d height=%d format=%d mTransformHint=%d", width, height, format, mTransformHint); @@ -225,11 +218,9 @@ void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, mSize = mRequestedSize; SurfaceComposerClient::Transaction* destFrameTransaction = (outTransaction) ? outTransaction : &t; - if (mSurfaceControl != nullptr) { - destFrameTransaction->setDestinationFrame(mSurfaceControl, - Rect(0, 0, newSize.getWidth(), - newSize.getHeight())); - } + destFrameTransaction->setDestinationFrame(mSurfaceControl, + Rect(0, 0, newSize.getWidth(), + newSize.getHeight())); applyTransaction = true; } } @@ -511,8 +502,7 @@ void BLASTBufferQueue::acquireNextBufferLocked( std::bind(releaseBufferCallbackThunk, wp<BLASTBufferQueue>(this) /* callbackContext */, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); sp<Fence> fence = bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE; - t->setBuffer(mSurfaceControl, buffer, fence, bufferItem.mFrameNumber, releaseCallbackId, - releaseBufferCallback); + t->setBuffer(mSurfaceControl, buffer, fence, bufferItem.mFrameNumber, releaseBufferCallback); t->setDataspace(mSurfaceControl, static_cast<ui::Dataspace>(bufferItem.mDataSpace)); t->setHdrMetadata(mSurfaceControl, bufferItem.mHdrMetadata); t->setSurfaceDamageRegion(mSurfaceControl, bufferItem.mSurfaceDamage); @@ -626,7 +616,7 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { if (bufferData) { BQA_LOGD("Releasing previous buffer when syncing: framenumber=%" PRIu64, bufferData->frameNumber); - releaseBuffer(bufferData->releaseCallbackId, bufferData->acquireFence); + releaseBuffer(bufferData->generateReleaseCallbackId(), bufferData->acquireFence); // Because we just released a buffer, we know there's no need to wait for a free // buffer. mayNeedToWaitForBuffer = false; @@ -640,7 +630,7 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { // add to shadow queue mNumFrameAvailable++; - if (mWaitForTransactionCallback && mNumFrameAvailable == 2) { + if (mWaitForTransactionCallback && mNumFrameAvailable >= 2) { acquireAndReleaseBuffer(); } ATRACE_INT(mQueuedBufferTrace.c_str(), @@ -717,7 +707,7 @@ bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) { // of the buffer, the next acquire may return with NO_BUFFER_AVAILABLE. bool BLASTBufferQueue::maxBuffersAcquired(bool includeExtraAcquire) const { int maxAcquiredBuffers = mMaxAcquiredBuffers + (includeExtraAcquire ? 2 : 1); - return mNumAcquired == maxAcquiredBuffers; + return mNumAcquired >= maxAcquiredBuffers; } class BBQSurface : public Surface { @@ -991,4 +981,53 @@ uint64_t BLASTBufferQueue::getLastAcquiredFrameNum() { return mLastAcquiredFrameNumber; } +void BLASTBufferQueue::abandon() { + std::unique_lock _lock{mMutex}; + // flush out the shadow queue + while (mNumFrameAvailable > 0) { + acquireAndReleaseBuffer(); + } + + // Clear submitted buffer states + mNumAcquired = 0; + mSubmitted.clear(); + mPendingRelease.clear(); + + if (!mPendingTransactions.empty()) { + BQA_LOGD("Applying pending transactions on abandon %d", + static_cast<uint32_t>(mPendingTransactions.size())); + SurfaceComposerClient::Transaction t; + mergePendingTransactions(&t, std::numeric_limits<uint64_t>::max() /* frameNumber */); + t.setApplyToken(mApplyToken).apply(); + } + + // Clear sync states + if (mWaitForTransactionCallback) { + BQA_LOGD("mWaitForTransactionCallback cleared"); + mWaitForTransactionCallback = false; + } + + if (mSyncTransaction != nullptr) { + BQA_LOGD("mSyncTransaction cleared mAcquireSingleBuffer=%s", + mAcquireSingleBuffer ? "true" : "false"); + mSyncTransaction = nullptr; + mAcquireSingleBuffer = false; + } + + // abandon buffer queue + if (mBufferItemConsumer != nullptr) { + mBufferItemConsumer->abandon(); + mBufferItemConsumer->setFrameAvailableListener(nullptr); + mBufferItemConsumer->setBufferFreedListener(nullptr); + } + mBufferItemConsumer = nullptr; + mConsumer = nullptr; + mProducer = nullptr; +} + +bool BLASTBufferQueue::isSameSurfaceControl(const sp<SurfaceControl>& surfaceControl) const { + std::unique_lock _lock{mMutex}; + return SurfaceControl::isSameSurface(mSurfaceControl, surfaceControl); +} + } // namespace android diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index ec0573a1a9..acd9ac5a93 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -677,6 +677,10 @@ status_t LayerCaptureArgs::read(const Parcel& input) { return NO_ERROR; } +ReleaseCallbackId BufferData::generateReleaseCallbackId() const { + return {buffer->getId(), frameNumber}; +} + status_t BufferData::write(Parcel& output) const { SAFE_PARCEL(output.writeInt32, flags.get()); diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 665363627a..b10c3848fa 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -736,10 +736,10 @@ void SurfaceComposerClient::Transaction::releaseBufferIfOverwriting(const layer_ // if the callback is in process, run on a different thread to avoid any lock contigency // issues in the client. SurfaceComposerClient::getDefault() - ->mReleaseCallbackThread.addReleaseCallback(state.bufferData.releaseCallbackId, - fence); + ->mReleaseCallbackThread + .addReleaseCallback(state.bufferData.generateReleaseCallbackId(), fence); } else { - listener->onReleaseBuffer(state.bufferData.releaseCallbackId, fence, UINT_MAX); + listener->onReleaseBuffer(state.bufferData.generateReleaseCallbackId(), fence, UINT_MAX); } } @@ -1335,7 +1335,7 @@ std::optional<BufferData> SurfaceComposerClient::Transaction::getAndClearBuffer( BufferData bufferData = s->bufferData; TransactionCompletedListener::getInstance()->removeReleaseBufferCallback( - bufferData.releaseCallbackId); + bufferData.generateReleaseCallbackId()); BufferData emptyBufferData; s->what &= ~layer_state_t::eBufferChanged; s->bufferData = emptyBufferData; @@ -1347,7 +1347,7 @@ std::optional<BufferData> SurfaceComposerClient::Transaction::getAndClearBuffer( SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffer( const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer, const std::optional<sp<Fence>>& fence, const std::optional<uint64_t>& frameNumber, - const ReleaseCallbackId& id, ReleaseBufferCallback callback) { + ReleaseBufferCallback callback) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; @@ -1371,7 +1371,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe if (mIsAutoTimestamp) { mDesiredPresentTime = systemTime(); } - setReleaseBufferCallback(&bufferData, id, callback); + setReleaseBufferCallback(&bufferData, callback); s->what |= layer_state_t::eBufferChanged; s->bufferData = bufferData; registerSurfaceControlForCallback(sc); @@ -1381,7 +1381,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe } void SurfaceComposerClient::Transaction::setReleaseBufferCallback(BufferData* bufferData, - const ReleaseCallbackId& id, ReleaseBufferCallback callback) { if (!callback) { return; @@ -1394,9 +1393,8 @@ void SurfaceComposerClient::Transaction::setReleaseBufferCallback(BufferData* bu } bufferData->releaseBufferListener = TransactionCompletedListener::getIInstance(); - bufferData->releaseCallbackId = id; auto listener = TransactionCompletedListener::getInstance(); - listener->setReleaseBufferCallback(id, callback); + listener->setReleaseBufferCallback(bufferData->generateReleaseCallbackId(), callback); } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDataspace( diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp index e92be01e15..8d356aaaa1 100644 --- a/libs/gui/WindowInfo.cpp +++ b/libs/gui/WindowInfo.cpp @@ -47,6 +47,10 @@ bool WindowInfo::isSpy() const { return inputFeatures.test(Feature::SPY); } +bool WindowInfo::interceptsStylus() const { + return inputFeatures.test(Feature::INTERCEPTS_STYLUS); +} + bool WindowInfo::overlaps(const WindowInfo* other) const { return frameLeft < other->frameRight && frameRight > other->frameLeft && frameTop < other->frameBottom && frameBottom > other->frameTop; diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 8a2f392e35..f77cfe6a69 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -38,11 +38,11 @@ class BufferItemConsumer; class BLASTBufferItemConsumer : public BufferItemConsumer { public: BLASTBufferItemConsumer(const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage, - int bufferCount, bool controlledByApp) + int bufferCount, bool controlledByApp, wp<BLASTBufferQueue> bbq) : BufferItemConsumer(consumer, consumerUsage, bufferCount, controlledByApp), + mBLASTBufferQueue(std::move(bbq)), mCurrentlyConnected(false), - mPreviouslyConnected(false), - mBLASTBufferQueue(nullptr) {} + mPreviouslyConnected(false) {} void onDisconnect() override; void addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps, @@ -53,21 +53,20 @@ public: CompositorTiming compositorTiming, nsecs_t latchTime, nsecs_t dequeueReadyTime) REQUIRES(mMutex); void getConnectionEvents(uint64_t frameNumber, bool* needsDisconnect); - void setBlastBufferQueue(BLASTBufferQueue* blastbufferqueue) REQUIRES(mMutex); protected: void onSidebandStreamChanged() override REQUIRES(mMutex); private: + const wp<BLASTBufferQueue> mBLASTBufferQueue; + uint64_t mCurrentFrameNumber = 0; Mutex mMutex; - std::mutex mBufferQueueMutex; ConsumerFrameEventHistory mFrameEventHistory GUARDED_BY(mMutex); std::queue<uint64_t> mDisconnectEvents GUARDED_BY(mMutex); bool mCurrentlyConnected GUARDED_BY(mMutex); bool mPreviouslyConnected GUARDED_BY(mMutex); - BLASTBufferQueue* mBLASTBufferQueue GUARDED_BY(mBufferQueueMutex); }; class BLASTBufferQueue @@ -82,6 +81,7 @@ public: return mProducer; } sp<Surface> getSurface(bool includeSurfaceControlHandle); + bool isSameSurfaceControl(const sp<SurfaceControl>& surfaceControl) const; void onBufferFreed(const wp<GraphicBuffer>&/* graphicBuffer*/) override { /* TODO */ } void onFrameReplaced(const BufferItem& item) override; @@ -109,6 +109,7 @@ public: uint32_t getLastTransformHint() const; uint64_t getLastAcquiredFrameNum(); + void abandon(); virtual ~BLASTBufferQueue(); @@ -145,15 +146,15 @@ private: std::string mQueuedBufferTrace; sp<SurfaceControl> mSurfaceControl; - std::mutex mMutex; + mutable std::mutex mMutex; std::condition_variable mCallbackCV; // BufferQueue internally allows 1 more than // the max to be acquired int32_t mMaxAcquiredBuffers = 1; - int32_t mNumFrameAvailable GUARDED_BY(mMutex); - int32_t mNumAcquired GUARDED_BY(mMutex); + int32_t mNumFrameAvailable GUARDED_BY(mMutex) = 0; + int32_t mNumAcquired GUARDED_BY(mMutex) = 0; // Keep a reference to the submitted buffers so we can release when surfaceflinger drops the // buffer or the buffer has been presented and a new buffer is ready to be presented. diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index a0d3162afe..e48f52d13d 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -77,12 +77,6 @@ struct BufferData { // buffer id to identify the buffer. sp<ITransactionCompletedListener> releaseBufferListener = nullptr; - // Keeps track of the release callback id associated with the listener. This - // is not sent to the server since the id can be reconstructed there. This - // is used to remove the old callback from the client process map if it is - // overwritten by another setBuffer call. - ReleaseCallbackId releaseCallbackId = ReleaseCallbackId::INVALID_ID; - // Stores which endpoint the release information should be sent to. We don't want to send the // releaseCallbackId and release fence to all listeners so we store which listener the setBuffer // was called with. @@ -92,6 +86,9 @@ struct BufferData { client_cache_t cachedBuffer; + // Generates the release callback id based on the buffer id and frame number. + // This is used as an identifier when release callbacks are invoked. + ReleaseCallbackId generateReleaseCallbackId() const; status_t write(Parcel& output) const; status_t read(const Parcel& input); }; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 87606d6c8e..b739b3c8bf 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -426,7 +426,7 @@ public: void cacheBuffers(); void registerSurfaceControlForCallback(const sp<SurfaceControl>& sc); - void setReleaseBufferCallback(BufferData*, const ReleaseCallbackId&, ReleaseBufferCallback); + void setReleaseBufferCallback(BufferData*, ReleaseBufferCallback); public: Transaction(); @@ -500,7 +500,6 @@ public: Transaction& setBuffer(const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer, const std::optional<sp<Fence>>& fence = std::nullopt, const std::optional<uint64_t>& frameNumber = std::nullopt, - const ReleaseCallbackId& id = ReleaseCallbackId::INVALID_ID, ReleaseBufferCallback callback = nullptr); std::optional<BufferData> getAndClearBuffer(const sp<SurfaceControl>& sc); Transaction& setDataspace(const sp<SurfaceControl>& sc, ui::Dataspace dataspace); diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index 808afe40dd..2bfaec8d03 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -17,6 +17,7 @@ #pragma once #include <android/gui/TouchOcclusionMode.h> +#include <android/os/IInputConstants.h> #include <binder/Parcel.h> #include <binder/Parcelable.h> #include <ftl/Flags.h> @@ -131,13 +132,23 @@ struct WindowInfo : public Parcelable { ftl_last = FIRST_SYSTEM_WINDOW + 15 }; + // This is a conversion of os::IInputConstants::InputFeature to an enum backed by an unsigned + // type. This indicates that they are flags, so it can be used with ftl/enum.h. enum class Feature : uint32_t { - DISABLE_TOUCH_PAD_GESTURES = 1u << 0, - NO_INPUT_CHANNEL = 1u << 1, - DISABLE_USER_ACTIVITY = 1u << 2, - DROP_INPUT = 1u << 3, - DROP_INPUT_IF_OBSCURED = 1u << 4, - SPY = 1u << 5, + // clang-format off + NO_INPUT_CHANNEL = + static_cast<uint32_t>(os::IInputConstants::InputFeature::NO_INPUT_CHANNEL), + DISABLE_USER_ACTIVITY = + static_cast<uint32_t>(os::IInputConstants::InputFeature::DISABLE_USER_ACTIVITY), + DROP_INPUT = + static_cast<uint32_t>(os::IInputConstants::InputFeature::DROP_INPUT), + DROP_INPUT_IF_OBSCURED = + static_cast<uint32_t>(os::IInputConstants::InputFeature::DROP_INPUT_IF_OBSCURED), + SPY = + static_cast<uint32_t>(os::IInputConstants::InputFeature::SPY), + INTERCEPTS_STYLUS = + static_cast<uint32_t>(os::IInputConstants::InputFeature::INTERCEPTS_STYLUS), + // clang-format on }; /* These values are filled in by the WM and passed through SurfaceFlinger @@ -218,6 +229,8 @@ struct WindowInfo : public Parcelable { bool isSpy() const; + bool interceptsStylus() const; + bool overlaps(const WindowInfo* other) const; bool operator==(const WindowInfo& inputChannel) const; diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index 48b8621be1..42a32f3b42 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -1069,6 +1069,94 @@ TEST_F(BLASTBufferQueueTest, SetSyncTransactionAcquireMultipleBuffers) { checkScreenCapture(255, 0, 0, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); } +// This test will currently fail because the old surfacecontrol will steal the last presented buffer +// until the old surface control is destroyed. This is not necessarily a bug but to document a +// limitation with the update API and to test any changes to make the api more robust. The current +// approach for the client is to recreate the blastbufferqueue when the surfacecontrol updates. +TEST_F(BLASTBufferQueueTest, DISABLED_DisconnectProducerTest) { + BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); + std::vector<sp<SurfaceControl>> surfaceControls; + sp<IGraphicBufferProducer> igbProducer; + for (int i = 0; i < 10; i++) { + sp<SurfaceControl> sc = + mClient->createSurface(String8("TestSurface"), mDisplayWidth, mDisplayHeight, + PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceBufferState, + /*parent*/ nullptr); + Transaction() + .setLayerStack(mSurfaceControl, ui::DEFAULT_LAYER_STACK) + .setLayer(mSurfaceControl, std::numeric_limits<int32_t>::max()) + .show(mSurfaceControl) + .setDataspace(mSurfaceControl, ui::Dataspace::V0_SRGB) + .apply(true); + surfaceControls.push_back(sc); + adapter.update(sc, mDisplayWidth, mDisplayHeight); + + setUpProducer(adapter, igbProducer); + Transaction next; + queueBuffer(igbProducer, 0, 255, 0, 0); + queueBuffer(igbProducer, 0, 0, 255, 0); + adapter.setSyncTransaction(&next, false); + queueBuffer(igbProducer, 255, 0, 0, 0); + + CallbackHelper transactionCallback; + next.addTransactionCompletedCallback(transactionCallback.function, + transactionCallback.getContext()) + .apply(); + + CallbackData callbackData; + transactionCallback.getCallbackData(&callbackData); + // capture screen and verify that it is red + ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(255, 0, 0, + {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); + igbProducer->disconnect(NATIVE_WINDOW_API_CPU); + } +} + +// See DISABLED_DisconnectProducerTest +TEST_F(BLASTBufferQueueTest, DISABLED_UpdateSurfaceControlTest) { + BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); + std::vector<sp<SurfaceControl>> surfaceControls; + sp<IGraphicBufferProducer> igbProducer; + for (int i = 0; i < 10; i++) { + sp<SurfaceControl> sc = + mClient->createSurface(String8("TestSurface"), mDisplayWidth, mDisplayHeight, + PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceBufferState, + /*parent*/ nullptr); + Transaction() + .setLayerStack(mSurfaceControl, ui::DEFAULT_LAYER_STACK) + .setLayer(mSurfaceControl, std::numeric_limits<int32_t>::max()) + .show(mSurfaceControl) + .setDataspace(mSurfaceControl, ui::Dataspace::V0_SRGB) + .apply(true); + surfaceControls.push_back(sc); + adapter.update(sc, mDisplayWidth, mDisplayHeight); + setUpProducer(adapter, igbProducer); + + Transaction next; + queueBuffer(igbProducer, 0, 255, 0, 0); + queueBuffer(igbProducer, 0, 0, 255, 0); + adapter.setSyncTransaction(&next, false); + queueBuffer(igbProducer, 255, 0, 0, 0); + + CallbackHelper transactionCallback; + next.addTransactionCompletedCallback(transactionCallback.function, + transactionCallback.getContext()) + .apply(); + + CallbackData callbackData; + transactionCallback.getCallbackData(&callbackData); + // capture screen and verify that it is red + ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(255, 0, 0, + {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); + } +} + class TestProducerListener : public BnProducerListener { public: sp<IGraphicBufferProducer> mIgbp; diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index f960e07d2f..6f1263bb89 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -46,6 +46,8 @@ #include <ui/Rect.h> #include <ui/Region.h> +#include <private/android_filesystem_config.h> + using android::os::IInputFlinger; using android::hardware::graphics::common::V1_1::BufferUsage; @@ -179,6 +181,25 @@ public: EXPECT_EQ(flags, mev->getFlags() & flags); } + void expectTapInDisplayCoordinates(int displayX, int displayY) { + InputEvent *ev = consumeEvent(); + ASSERT_NE(ev, nullptr); + ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, ev->getType()); + MotionEvent *mev = static_cast<MotionEvent *>(ev); + EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, mev->getAction()); + const PointerCoords &coords = *mev->getRawPointerCoords(0 /*pointerIndex*/); + EXPECT_EQ(displayX, coords.getX()); + EXPECT_EQ(displayY, coords.getY()); + EXPECT_EQ(0, mev->getFlags() & VERIFIED_MOTION_EVENT_FLAGS); + + ev = consumeEvent(); + ASSERT_NE(ev, nullptr); + ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, ev->getType()); + mev = static_cast<MotionEvent *>(ev); + EXPECT_EQ(AMOTION_EVENT_ACTION_UP, mev->getAction()); + EXPECT_EQ(0, mev->getFlags() & VERIFIED_MOTION_EVENT_FLAGS); + } + void expectKey(uint32_t keycode) { InputEvent *ev = consumeEvent(); ASSERT_NE(ev, nullptr); @@ -969,31 +990,96 @@ TEST_F(InputSurfacesTest, drop_input_policy) { class MultiDisplayTests : public InputSurfacesTest { public: MultiDisplayTests() : InputSurfacesTest() { ProcessState::self()->startThreadPool(); } - void TearDown() { - if (mVirtualDisplay) { - SurfaceComposerClient::destroyDisplay(mVirtualDisplay); + void TearDown() override { + for (auto &token : mVirtualDisplays) { + SurfaceComposerClient::destroyDisplay(token); } InputSurfacesTest::TearDown(); } - void createDisplay(int32_t width, int32_t height, bool isSecure, ui::LayerStack layerStack) { + void createDisplay(int32_t width, int32_t height, bool isSecure, ui::LayerStack layerStack, + bool receivesInput = true, int32_t offsetX = 0, int32_t offsetY = 0) { sp<IGraphicBufferConsumer> consumer; - BufferQueue::createBufferQueue(&mProducer, &consumer); + sp<IGraphicBufferProducer> producer; + BufferQueue::createBufferQueue(&producer, &consumer); consumer->setConsumerName(String8("Virtual disp consumer")); consumer->setDefaultBufferSize(width, height); + mProducers.push_back(producer); - mVirtualDisplay = SurfaceComposerClient::createDisplay(String8("VirtualDisplay"), isSecure); + std::string name = "VirtualDisplay"; + name += std::to_string(mVirtualDisplays.size()); + sp<IBinder> token = SurfaceComposerClient::createDisplay(String8(name.c_str()), isSecure); SurfaceComposerClient::Transaction t; - t.setDisplaySurface(mVirtualDisplay, mProducer); - t.setDisplayFlags(mVirtualDisplay, 0x01 /* DisplayDevice::eReceivesInput */); - t.setDisplayLayerStack(mVirtualDisplay, layerStack); + t.setDisplaySurface(token, producer); + t.setDisplayFlags(token, receivesInput ? 0x01 /* DisplayDevice::eReceivesInput */ : 0); + t.setDisplayLayerStack(token, layerStack); + t.setDisplayProjection(token, ui::ROTATION_0, {0, 0, width, height}, + {offsetX, offsetY, offsetX + width, offsetY + height}); t.apply(true); + + mVirtualDisplays.push_back(token); } - sp<IBinder> mVirtualDisplay; - sp<IGraphicBufferProducer> mProducer; + std::vector<sp<IBinder>> mVirtualDisplays; + std::vector<sp<IGraphicBufferProducer>> mProducers; }; +TEST_F(MultiDisplayTests, drop_input_if_layer_on_invalid_display) { + ui::LayerStack layerStack = ui::LayerStack::fromValue(42); + // Do not create a display associated with the LayerStack. + std::unique_ptr<InputSurface> surface = makeSurface(100, 100); + surface->doTransaction([&](auto &t, auto &sc) { t.setLayerStack(sc, layerStack); }); + surface->showAt(100, 100); + + injectTapOnDisplay(101, 101, layerStack.id); + surface->requestFocus(layerStack.id); + injectKeyOnDisplay(AKEYCODE_V, layerStack.id); + + EXPECT_EQ(surface->consumeEvent(100), nullptr); +} + +TEST_F(MultiDisplayTests, virtual_display_receives_input) { + ui::LayerStack layerStack = ui::LayerStack::fromValue(42); + createDisplay(1000, 1000, false /*isSecure*/, layerStack); + std::unique_ptr<InputSurface> surface = makeSurface(100, 100); + surface->doTransaction([&](auto &t, auto &sc) { t.setLayerStack(sc, layerStack); }); + surface->showAt(100, 100); + + injectTapOnDisplay(101, 101, layerStack.id); + surface->expectTap(1, 1); + + surface->requestFocus(layerStack.id); + surface->assertFocusChange(true); + injectKeyOnDisplay(AKEYCODE_V, layerStack.id); + surface->expectKey(AKEYCODE_V); +} + +/** + * When multiple DisplayDevices are mapped to the same layerStack, use the configuration for the + * display that can receive input. + */ +TEST_F(MultiDisplayTests, many_to_one_display_mapping) { + ui::LayerStack layerStack = ui::LayerStack::fromValue(42); + createDisplay(1000, 1000, false /*isSecure*/, layerStack, false /*receivesInput*/, + 100 /*offsetX*/, 100 /*offsetY*/); + createDisplay(1000, 1000, false /*isSecure*/, layerStack, true /*receivesInput*/, + 200 /*offsetX*/, 200 /*offsetY*/); + createDisplay(1000, 1000, false /*isSecure*/, layerStack, false /*receivesInput*/, + 300 /*offsetX*/, 300 /*offsetY*/); + std::unique_ptr<InputSurface> surface = makeSurface(100, 100); + surface->doTransaction([&](auto &t, auto &sc) { t.setLayerStack(sc, layerStack); }); + surface->showAt(10, 10); + + // Input injection happens in logical display coordinates. + injectTapOnDisplay(11, 11, layerStack.id); + // Expect that the display transform for the display that receives input was used. + surface->expectTapInDisplayCoordinates(211, 211); + + surface->requestFocus(layerStack.id); + surface->assertFocusChange(true); + injectKeyOnDisplay(AKEYCODE_V, layerStack.id); +} + TEST_F(MultiDisplayTests, drop_input_for_secure_layer_on_nonsecure_display) { ui::LayerStack layerStack = ui::LayerStack::fromValue(42); createDisplay(1000, 1000, false /*isSecure*/, layerStack); @@ -1004,7 +1090,7 @@ TEST_F(MultiDisplayTests, drop_input_for_secure_layer_on_nonsecure_display) { }); surface->showAt(100, 100); - injectTap(101, 101); + injectTapOnDisplay(101, 101, layerStack.id); EXPECT_EQ(surface->consumeEvent(100), nullptr); @@ -1016,7 +1102,13 @@ TEST_F(MultiDisplayTests, drop_input_for_secure_layer_on_nonsecure_display) { TEST_F(MultiDisplayTests, dont_drop_input_for_secure_layer_on_secure_display) { ui::LayerStack layerStack = ui::LayerStack::fromValue(42); + + // Create the secure display as system, because only certain users can create secure displays. + seteuid(AID_SYSTEM); createDisplay(1000, 1000, true /*isSecure*/, layerStack); + // Change the uid back to root. + seteuid(AID_ROOT); + std::unique_ptr<InputSurface> surface = makeSurface(100, 100); surface->doTransaction([&](auto &t, auto &sc) { t.setFlags(sc, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure); diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index f0b97a7ba8..84dba84e2b 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -344,11 +344,6 @@ void PointerCoords::scale(float globalScaleFactor, float windowXScale, float win scaleAxisValue(*this, AMOTION_EVENT_AXIS_RELATIVE_Y, windowYScale); } -void PointerCoords::applyOffset(float xOffset, float yOffset) { - setAxisValue(AMOTION_EVENT_AXIS_X, getX() + xOffset); - setAxisValue(AMOTION_EVENT_AXIS_Y, getY() + yOffset); -} - #ifdef __linux__ status_t PointerCoords::readFromParcel(Parcel* parcel) { bits = parcel->readInt64(); diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp index 3baeb55009..2039fa6553 100644 --- a/libs/input/KeyCharacterMap.cpp +++ b/libs/input/KeyCharacterMap.cpp @@ -86,10 +86,13 @@ static String8 toString(const char16_t* chars, size_t numChars) { // --- KeyCharacterMap --- -KeyCharacterMap::KeyCharacterMap() : mType(KeyboardType::UNKNOWN) {} +KeyCharacterMap::KeyCharacterMap(const std::string& filename) + : mType(KeyboardType::UNKNOWN), mLoadFileName(filename) {} KeyCharacterMap::KeyCharacterMap(const KeyCharacterMap& other) : mType(other.mType), + mLoadFileName(other.mLoadFileName), + mLayoutOverlayApplied(other.mLayoutOverlayApplied), mKeysByScanCode(other.mKeysByScanCode), mKeysByUsageCode(other.mKeysByUsageCode) { for (size_t i = 0; i < other.mKeys.size(); i++) { @@ -98,16 +101,19 @@ KeyCharacterMap::KeyCharacterMap(const KeyCharacterMap& other) } KeyCharacterMap::~KeyCharacterMap() { - for (size_t i = 0; i < mKeys.size(); i++) { - Key* key = mKeys.editValueAt(i); - delete key; - } + clear(); } bool KeyCharacterMap::operator==(const KeyCharacterMap& other) const { if (mType != other.mType) { return false; } + if (mLoadFileName != other.mLoadFileName) { + return false; + } + if (mLayoutOverlayApplied != other.mLayoutOverlayApplied) { + return false; + } if (mKeys.size() != other.mKeys.size() || mKeysByScanCode.size() != other.mKeysByScanCode.size() || mKeysByUsageCode.size() != other.mKeysByUsageCode.size()) { @@ -146,6 +152,10 @@ bool KeyCharacterMap::operator==(const KeyCharacterMap& other) const { return true; } +bool KeyCharacterMap::operator!=(const KeyCharacterMap& other) const { + return !(*this == other); +} + base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::load(const std::string& filename, Format format) { Tokenizer* tokenizer; @@ -153,12 +163,18 @@ base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::load(const std:: if (status) { return Errorf("Error {} opening key character map file {}.", status, filename.c_str()); } + std::shared_ptr<KeyCharacterMap> map = + std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(filename)); + if (!map.get()) { + ALOGE("Error allocating key character map."); + return Errorf("Error allocating key character map."); + } std::unique_ptr<Tokenizer> t(tokenizer); - auto ret = load(t.get(), format); - if (ret.ok()) { - (*ret)->mLoadFileName = filename; + status = map->load(t.get(), format); + if (status == OK) { + return map; } - return ret; + return Errorf("Load KeyCharacterMap failed {}.", status); } base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::loadContents( @@ -169,40 +185,67 @@ base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::loadContents( ALOGE("Error %d opening key character map.", status); return Errorf("Error {} opening key character map.", status); } + std::shared_ptr<KeyCharacterMap> map = + std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(filename)); + if (!map.get()) { + ALOGE("Error allocating key character map."); + return Errorf("Error allocating key character map."); + } std::unique_ptr<Tokenizer> t(tokenizer); - auto ret = load(t.get(), format); - if (ret.ok()) { - (*ret)->mLoadFileName = filename; + status = map->load(t.get(), format); + if (status == OK) { + return map; } - return ret; + return Errorf("Load KeyCharacterMap failed {}.", status); } -base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::load(Tokenizer* tokenizer, - Format format) { +status_t KeyCharacterMap::load(Tokenizer* tokenizer, Format format) { status_t status = OK; - std::shared_ptr<KeyCharacterMap> map = std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap()); - if (!map.get()) { - ALOGE("Error allocating key character map."); - return Errorf("Error allocating key character map."); - } #if DEBUG_PARSER_PERFORMANCE nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); #endif - Parser parser(map.get(), tokenizer, format); + Parser parser(this, tokenizer, format); status = parser.parse(); #if DEBUG_PARSER_PERFORMANCE nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.", tokenizer->getFilename().string(), tokenizer->getLineNumber(), elapsedTime / 1000000.0); #endif - if (status == OK) { - return map; + if (status != OK) { + ALOGE("Loading KeyCharacterMap failed with status %s", statusToString(status).c_str()); } + return status; +} - return Errorf("Load KeyCharacterMap failed {}.", status); +void KeyCharacterMap::clear() { + mKeysByScanCode.clear(); + mKeysByUsageCode.clear(); + for (size_t i = 0; i < mKeys.size(); i++) { + Key* key = mKeys.editValueAt(i); + delete key; + } + mKeys.clear(); + mLayoutOverlayApplied = false; + mType = KeyboardType::UNKNOWN; +} + +status_t KeyCharacterMap::reloadBaseFromFile() { + clear(); + Tokenizer* tokenizer; + status_t status = Tokenizer::open(String8(mLoadFileName.c_str()), &tokenizer); + if (status) { + ALOGE("Error %s opening key character map file %s.", statusToString(status).c_str(), + mLoadFileName.c_str()); + return status; + } + std::unique_ptr<Tokenizer> t(tokenizer); + return load(t.get(), KeyCharacterMap::Format::BASE); } void KeyCharacterMap::combine(const KeyCharacterMap& overlay) { + if (mLayoutOverlayApplied) { + reloadBaseFromFile(); + } for (size_t i = 0; i < overlay.mKeys.size(); i++) { int32_t keyCode = overlay.mKeys.keyAt(i); Key* key = overlay.mKeys.valueAt(i); @@ -224,7 +267,7 @@ void KeyCharacterMap::combine(const KeyCharacterMap& overlay) { mKeysByUsageCode.replaceValueFor(overlay.mKeysByUsageCode.keyAt(i), overlay.mKeysByUsageCode.valueAt(i)); } - mLoadFileName = overlay.mLoadFileName; + mLayoutOverlayApplied = true; } KeyCharacterMap::KeyboardType KeyCharacterMap::getKeyboardType() const { @@ -636,8 +679,11 @@ std::shared_ptr<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel) ALOGE("%s: Null parcel", __func__); return nullptr; } - std::shared_ptr<KeyCharacterMap> map = std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap()); + std::string loadFileName = parcel->readCString(); + std::shared_ptr<KeyCharacterMap> map = + std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(loadFileName)); map->mType = static_cast<KeyCharacterMap::KeyboardType>(parcel->readInt32()); + map->mLayoutOverlayApplied = parcel->readBool(); size_t numKeys = parcel->readInt32(); if (parcel->errorCheck()) { return nullptr; @@ -687,6 +733,30 @@ std::shared_ptr<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel) return nullptr; } } + size_t numKeysByScanCode = parcel->readInt32(); + if (parcel->errorCheck()) { + return nullptr; + } + for (size_t i = 0; i < numKeysByScanCode; i++) { + int32_t key = parcel->readInt32(); + int32_t value = parcel->readInt32(); + map->mKeysByScanCode.add(key, value); + if (parcel->errorCheck()) { + return nullptr; + } + } + size_t numKeysByUsageCode = parcel->readInt32(); + if (parcel->errorCheck()) { + return nullptr; + } + for (size_t i = 0; i < numKeysByUsageCode; i++) { + int32_t key = parcel->readInt32(); + int32_t value = parcel->readInt32(); + map->mKeysByUsageCode.add(key, value); + if (parcel->errorCheck()) { + return nullptr; + } + } return map; } @@ -695,7 +765,9 @@ void KeyCharacterMap::writeToParcel(Parcel* parcel) const { ALOGE("%s: Null parcel", __func__); return; } + parcel->writeCString(mLoadFileName.c_str()); parcel->writeInt32(static_cast<int32_t>(mType)); + parcel->writeBool(mLayoutOverlayApplied); size_t numKeys = mKeys.size(); parcel->writeInt32(numKeys); @@ -715,6 +787,18 @@ void KeyCharacterMap::writeToParcel(Parcel* parcel) const { } parcel->writeInt32(0); } + size_t numKeysByScanCode = mKeysByScanCode.size(); + parcel->writeInt32(numKeysByScanCode); + for (size_t i = 0; i < numKeysByScanCode; i++) { + parcel->writeInt32(mKeysByScanCode.keyAt(i)); + parcel->writeInt32(mKeysByScanCode.valueAt(i)); + } + size_t numKeysByUsageCode = mKeysByUsageCode.size(); + parcel->writeInt32(numKeysByUsageCode); + for (size_t i = 0; i < numKeysByUsageCode; i++) { + parcel->writeInt32(mKeysByUsageCode.keyAt(i)); + parcel->writeInt32(mKeysByUsageCode.valueAt(i)); + } } #endif // __linux__ diff --git a/libs/input/android/os/IInputConstants.aidl b/libs/input/android/os/IInputConstants.aidl index 474a1e410d..829bbdd0b7 100644 --- a/libs/input/android/os/IInputConstants.aidl +++ b/libs/input/android/os/IInputConstants.aidl @@ -25,13 +25,6 @@ interface IInputConstants // android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS. const int UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS = 5000; // 5 seconds - // Compatibility changes. - /** - * TODO(b/157929241): remove this before closing the bug. This is needed temporarily - * to identify apps that are using this flag. - */ - const long BLOCK_FLAG_SLIPPERY = 157929241; - // Indicate invalid battery capacity const int INVALID_BATTERY_CAPACITY = -1; @@ -53,4 +46,53 @@ interface IInputConstants * set of flags, including in input/Input.h and in android/input.h. */ const int INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT = 0x800; + + @Backing(type="int") + enum InputFeature { + /** + * Does not construct an input channel for this window. The channel will therefore + * be incapable of receiving input. + */ + NO_INPUT_CHANNEL = 0x00000002, + + /** + * When this window has focus, does not call user activity for all input events so + * the application will have to do it itself. Should only be used by + * the keyguard and phone app. + * + * Should only be used by the keyguard and phone app. + */ + DISABLE_USER_ACTIVITY = 0x00000004, + + /** + * Internal flag used to indicate that input should be dropped on this window. + */ + DROP_INPUT = 0x00000008, + + /** + * Internal flag used to indicate that input should be dropped on this window if this window + * is obscured. + */ + DROP_INPUT_IF_OBSCURED = 0x00000010, + + /** + * An input spy window. This window will receive all pointer events within its touchable + * area, but will will not stop events from being sent to other windows below it in z-order. + * An input event will be dispatched to all spy windows above the top non-spy window at the + * event's coordinates. + */ + SPY = 0x00000020, + + /** + * When used with the window flag {@link #FLAG_NOT_TOUCHABLE}, this window will continue + * to receive events from a stylus device within its touchable region. All other pointer + * events, such as from a mouse or touchscreen, will be dispatched to the windows behind it. + * + * This input feature has no effect when the window flag {@link #FLAG_NOT_TOUCHABLE} is + * not set. + * + * The window must be a trusted overlay to use this input feature. + */ + INTERCEPTS_STYLUS = 0x00000040, + } } diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp index 18ab1cb522..6ffe8518b6 100644 --- a/libs/input/tests/Android.bp +++ b/libs/input/tests/Android.bp @@ -37,6 +37,7 @@ cc_test { "libui", "libutils", ], + data: ["data/*.kcm"], test_suites: ["device-tests"], } @@ -59,5 +60,5 @@ cc_library_static { "libbinder", "libui", "libbase", - ] + ], } diff --git a/libs/input/tests/InputDevice_test.cpp b/libs/input/tests/InputDevice_test.cpp index f8f2f4e931..61e88df11d 100644 --- a/libs/input/tests/InputDevice_test.cpp +++ b/libs/input/tests/InputDevice_test.cpp @@ -20,6 +20,7 @@ #include <input/InputDevice.h> #include <input/KeyLayoutMap.h> #include <input/Keyboard.h> +#include "android-base/file.h" namespace android { @@ -82,4 +83,53 @@ TEST_F(InputDeviceKeyMapTest, keyCharacterMapParcelingTest) { ASSERT_EQ(*map, *mKeyMap.keyCharacterMap); } +TEST_F(InputDeviceKeyMapTest, keyCharacterMapWithOverlayParcelingTest) { + Parcel parcel; + std::string overlayPath = base::GetExecutableDirectory() + "/data/german.kcm"; + base::Result<std::shared_ptr<KeyCharacterMap>> overlay = + KeyCharacterMap::load(overlayPath, KeyCharacterMap::Format::OVERLAY); + ASSERT_TRUE(overlay.ok()) << "Cannot load KeyCharacterMap at " << overlayPath; + mKeyMap.keyCharacterMap->combine(*overlay->get()); + mKeyMap.keyCharacterMap->writeToParcel(&parcel); + parcel.setDataPosition(0); + std::shared_ptr<KeyCharacterMap> map = KeyCharacterMap::readFromParcel(&parcel); + ASSERT_EQ(*map, *mKeyMap.keyCharacterMap); +} + +TEST_F(InputDeviceKeyMapTest, keyCharacteMapApplyMultipleOverlaysTest) { + std::string frenchOverlayPath = base::GetExecutableDirectory() + "/data/french.kcm"; + std::string englishOverlayPath = base::GetExecutableDirectory() + "/data/english_us.kcm"; + std::string germanOverlayPath = base::GetExecutableDirectory() + "/data/german.kcm"; + base::Result<std::shared_ptr<KeyCharacterMap>> frenchOverlay = + KeyCharacterMap::load(frenchOverlayPath, KeyCharacterMap::Format::OVERLAY); + ASSERT_TRUE(frenchOverlay.ok()) << "Cannot load KeyCharacterMap at " << frenchOverlayPath; + base::Result<std::shared_ptr<KeyCharacterMap>> englishOverlay = + KeyCharacterMap::load(englishOverlayPath, KeyCharacterMap::Format::OVERLAY); + ASSERT_TRUE(englishOverlay.ok()) << "Cannot load KeyCharacterMap at " << englishOverlayPath; + base::Result<std::shared_ptr<KeyCharacterMap>> germanOverlay = + KeyCharacterMap::load(germanOverlayPath, KeyCharacterMap::Format::OVERLAY); + ASSERT_TRUE(germanOverlay.ok()) << "Cannot load KeyCharacterMap at " << germanOverlayPath; + + // Apply the French overlay + mKeyMap.keyCharacterMap->combine(*frenchOverlay->get()); + // Copy the result for later + std::shared_ptr<KeyCharacterMap> frenchOverlaidKeyCharacterMap = + std::make_shared<KeyCharacterMap>(*mKeyMap.keyCharacterMap); + + // Apply the English overlay + mKeyMap.keyCharacterMap->combine(*englishOverlay->get()); + // Verify that the result is different from the French overlay result + ASSERT_NE(*mKeyMap.keyCharacterMap, *frenchOverlaidKeyCharacterMap); + + // Apply the German overlay + mKeyMap.keyCharacterMap->combine(*germanOverlay->get()); + // Verify that the result is different from the French overlay result + ASSERT_NE(*mKeyMap.keyCharacterMap, *frenchOverlaidKeyCharacterMap); + + // Apply the French overlay + mKeyMap.keyCharacterMap->combine(*frenchOverlay->get()); + // Verify that the result is the same like after applying it initially + ASSERT_EQ(*mKeyMap.keyCharacterMap, *frenchOverlaidKeyCharacterMap); +} + } // namespace android diff --git a/libs/input/tests/data/english_us.kcm b/libs/input/tests/data/english_us.kcm new file mode 100644 index 0000000000..d0ef027f85 --- /dev/null +++ b/libs/input/tests/data/english_us.kcm @@ -0,0 +1,311 @@ +# Copyright (C) 2021 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. + +# +# English (US) keyboard layout. +# Unlike the default (generic) keyboard layout, English (US) does not contain any +# special ALT characters. +# + +type OVERLAY + +### ROW 1 + +key GRAVE { + label: '`' + base: '`' + shift: '~' +} + +key 1 { + label: '1' + base: '1' + shift: '!' +} + +key 2 { + label: '2' + base: '2' + shift: '@' +} + +key 3 { + label: '3' + base: '3' + shift: '#' +} + +key 4 { + label: '4' + base: '4' + shift: '$' +} + +key 5 { + label: '5' + base: '5' + shift: '%' +} + +key 6 { + label: '6' + base: '6' + shift: '^' +} + +key 7 { + label: '7' + base: '7' + shift: '&' +} + +key 8 { + label: '8' + base: '8' + shift: '*' +} + +key 9 { + label: '9' + base: '9' + shift: '(' +} + +key 0 { + label: '0' + base: '0' + shift: ')' +} + +key MINUS { + label: '-' + base: '-' + shift: '_' +} + +key EQUALS { + label: '=' + base: '=' + shift: '+' +} + +### ROW 2 + +key Q { + label: 'Q' + base: 'q' + shift, capslock: 'Q' +} + +key W { + label: 'W' + base: 'w' + shift, capslock: 'W' +} + +key E { + label: 'E' + base: 'e' + shift, capslock: 'E' +} + +key R { + label: 'R' + base: 'r' + shift, capslock: 'R' +} + +key T { + label: 'T' + base: 't' + shift, capslock: 'T' +} + +key Y { + label: 'Y' + base: 'y' + shift, capslock: 'Y' +} + +key U { + label: 'U' + base: 'u' + shift, capslock: 'U' +} + +key I { + label: 'I' + base: 'i' + shift, capslock: 'I' +} + +key O { + label: 'O' + base: 'o' + shift, capslock: 'O' +} + +key P { + label: 'P' + base: 'p' + shift, capslock: 'P' +} + +key LEFT_BRACKET { + label: '[' + base: '[' + shift: '{' +} + +key RIGHT_BRACKET { + label: ']' + base: ']' + shift: '}' +} + +key BACKSLASH { + label: '\\' + base: '\\' + shift: '|' +} + +### ROW 3 + +key A { + label: 'A' + base: 'a' + shift, capslock: 'A' +} + +key S { + label: 'S' + base: 's' + shift, capslock: 'S' +} + +key D { + label: 'D' + base: 'd' + shift, capslock: 'D' +} + +key F { + label: 'F' + base: 'f' + shift, capslock: 'F' +} + +key G { + label: 'G' + base: 'g' + shift, capslock: 'G' +} + +key H { + label: 'H' + base: 'h' + shift, capslock: 'H' +} + +key J { + label: 'J' + base: 'j' + shift, capslock: 'J' +} + +key K { + label: 'K' + base: 'k' + shift, capslock: 'K' +} + +key L { + label: 'L' + base: 'l' + shift, capslock: 'L' +} + +key SEMICOLON { + label: ';' + base: ';' + shift: ':' +} + +key APOSTROPHE { + label: '\'' + base: '\'' + shift: '"' +} + +### ROW 4 + +key Z { + label: 'Z' + base: 'z' + shift, capslock: 'Z' +} + +key X { + label: 'X' + base: 'x' + shift, capslock: 'X' +} + +key C { + label: 'C' + base: 'c' + shift, capslock: 'C' +} + +key V { + label: 'V' + base: 'v' + shift, capslock: 'V' +} + +key B { + label: 'B' + base: 'b' + shift, capslock: 'B' +} + +key N { + label: 'N' + base: 'n' + shift, capslock: 'N' +} + +key M { + label: 'M' + base: 'm' + shift, capslock: 'M' +} + +key COMMA { + label: ',' + base: ',' + shift: '<' +} + +key PERIOD { + label: '.' + base: '.' + shift: '>' +} + +key SLASH { + label: '/' + base: '/' + shift: '?' +}
\ No newline at end of file diff --git a/libs/input/tests/data/french.kcm b/libs/input/tests/data/french.kcm new file mode 100644 index 0000000000..db69ea0430 --- /dev/null +++ b/libs/input/tests/data/french.kcm @@ -0,0 +1,336 @@ +# Copyright (C) 2021 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. + +# +# French keyboard layout, AZERTY style. +# + +type OVERLAY + +map key 16 A +map key 17 Z +map key 30 Q +map key 39 M +map key 44 W +map key 50 COMMA +map key 51 SEMICOLON +map key 86 PLUS + +### ROW 1 + +key GRAVE { + label: '\u00b2' + base: '\u00b2' +} + +key 1 { + label: '1' + base: '&' + shift: '1' +} + +key 2 { + label: '2' + base: '\u00e9' + shift: '2' + ralt: '~' +} + +key 3 { + label: '3' + base: '"' + shift: '3' + ralt: '#' +} + +key 4 { + label: '4' + base: '\'' + shift: '4' + ralt: '{' +} + +key 5 { + label: '5' + base: '(' + shift: '5' + ralt: '[' +} + +key 6 { + label: '6' + base: '-' + shift: '6' + ralt: '|' +} + +key 7 { + label: '7' + base: '\u00e8' + shift: '7' + ralt: '`' +} + +key 8 { + label: '8' + base: '_' + shift: '8' + ralt: '\\' +} + +key 9 { + label: '9' + base: '\u00e7' + shift: '9' + ralt: '^' +} + +key 0 { + label: '0' + base: '\u00e0' + shift: '0' + ralt: '@' +} + +key MINUS { + label: ')' + base: ')' + shift: '\u00b0' + ralt: ']' +} + +key EQUALS { + label: '=' + base: '=' + shift: '+' + ralt: '}' +} + +### ROW 2 + +key A { + label: 'A' + base: 'a' + shift, capslock: 'A' +} + +key Z { + label: 'Z' + base: 'z' + shift, capslock: 'Z' +} + +key E { + label: 'E' + base: 'e' + shift, capslock: 'E' + ralt: '\u20ac' +} + +key R { + label: 'R' + base: 'r' + shift, capslock: 'R' +} + +key T { + label: 'T' + base: 't' + shift, capslock: 'T' +} + +key Y { + label: 'Y' + base: 'y' + shift, capslock: 'Y' +} + +key U { + label: 'U' + base: 'u' + shift, capslock: 'U' +} + +key I { + label: 'I' + base: 'i' + shift, capslock: 'I' +} + +key O { + label: 'O' + base: 'o' + shift, capslock: 'O' +} + +key P { + label: 'P' + base: 'p' + shift, capslock: 'P' +} + +key LEFT_BRACKET { + label: '\u02c6' + base: '\u0302' + shift: '\u0308' +} + +key RIGHT_BRACKET { + label: '$' + base: '$' + shift: '\u00a3' + ralt: '\u00a4' +} + +### ROW 3 + +key Q { + label: 'Q' + base: 'q' + shift, capslock: 'Q' +} + +key S { + label: 'S' + base: 's' + shift, capslock: 'S' +} + +key D { + label: 'D' + base: 'd' + shift, capslock: 'D' +} + +key F { + label: 'F' + base: 'f' + shift, capslock: 'F' +} + +key G { + label: 'G' + base: 'g' + shift, capslock: 'G' +} + +key H { + label: 'H' + base: 'h' + shift, capslock: 'H' +} + +key J { + label: 'J' + base: 'j' + shift, capslock: 'J' +} + +key K { + label: 'K' + base: 'k' + shift, capslock: 'K' +} + +key L { + label: 'L' + base: 'l' + shift, capslock: 'L' +} + +key M { + label: 'M' + base: 'm' + shift, capslock: 'M' +} + +key APOSTROPHE { + label: '\u00f9' + base: '\u00f9' + shift: '%' +} + +key BACKSLASH { + label: '*' + base: '*' + shift: '\u00b5' +} + +### ROW 4 + +key PLUS { + label: '<' + base: '<' + shift: '>' +} + +key W { + label: 'W' + base: 'w' + shift, capslock: 'W' +} + +key X { + label: 'X' + base: 'x' + shift, capslock: 'X' +} + +key C { + label: 'C' + base: 'c' + shift, capslock: 'C' +} + +key V { + label: 'V' + base: 'v' + shift, capslock: 'V' +} + +key B { + label: 'B' + base: 'b' + shift, capslock: 'B' +} + +key N { + label: 'N' + base: 'n' + shift, capslock: 'N' +} + +key COMMA { + label: ',' + base: ',' + shift: '?' +} + +key SEMICOLON { + label: ';' + base: ';' + shift: '.' +} + +key PERIOD { + label: ':' + base: ':' + shift: '/' +} + +key SLASH { + label: '!' + base: '!' + shift: '\u00a7' +}
\ No newline at end of file diff --git a/libs/input/tests/data/german.kcm b/libs/input/tests/data/german.kcm new file mode 100644 index 0000000000..2fbc5e54e3 --- /dev/null +++ b/libs/input/tests/data/german.kcm @@ -0,0 +1,336 @@ +# Copyright (C) 2021 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. + +# +# German keyboard layout, QWERTZ style. +# + +type OVERLAY + +map key 12 SLASH # � ? \ +map key 21 Z +map key 44 Y +map key 53 MINUS # - _ +map key 86 PLUS # < > | + +map key usage 32 A # for testing purposes only +map key usage 67 B # for testing purposes only + +### ROW 1 + +key GRAVE { + label: '^' + base: '^' + shift: '\u00b0' +} + +key 1 { + label: '1' + base: '1' + shift: '!' +} + +key 2 { + label: '2' + base: '2' + shift: '"' + ralt: '\u00b2' +} + +key 3 { + label: '3' + base: '3' + shift: '\u00a7' + ralt: '\u00b3' +} + +key 4 { + label: '4' + base: '4' + shift: '$' +} + +key 5 { + label: '5' + base: '5' + shift: '%' +} + +key 6 { + label: '6' + base: '6' + shift: '&' +} + +key 7 { + label: '7' + base: '7' + shift: '/' + ralt: '{' +} + +key 8 { + label: '8' + base: '8' + shift: '(' + ralt: '[' +} + +key 9 { + label: '9' + base: '9' + shift: ')' + ralt: ']' +} + +key 0 { + label: '0' + base: '0' + shift: '=' + ralt: '}' +} + +key SLASH { + label: '\u00df' + base: '\u00df' + shift: '?' + ralt: '\\' +} + +key EQUALS { + label: '\u00b4' + base: '\u0301' + shift: '\u0300' +} + +### ROW 2 + +key Q { + label: 'Q' + base: 'q' + shift, capslock: 'Q' + ralt: '@' +} + +key W { + label: 'W' + base: 'w' + shift, capslock: 'W' +} + +key E { + label: 'E' + base: 'e' + shift, capslock: 'E' + ralt: '\u20ac' +} + +key R { + label: 'R' + base: 'r' + shift, capslock: 'R' +} + +key T { + label: 'T' + base: 't' + shift, capslock: 'T' +} + +key Z { + label: 'Z' + base: 'z' + shift, capslock: 'Z' +} + +key U { + label: 'U' + base: 'u' + shift, capslock: 'U' +} + +key I { + label: 'I' + base: 'i' + shift, capslock: 'I' +} + +key O { + label: 'O' + base: 'o' + shift, capslock: 'O' +} + +key P { + label: 'P' + base: 'p' + shift, capslock: 'P' +} + +key LEFT_BRACKET { + label: '\u00dc' + base: '\u00fc' + shift, capslock: '\u00dc' +} + +key RIGHT_BRACKET { + label: '+' + base: '+' + shift: '*' + ralt: '~' +} + +### ROW 3 + +key A { + label: 'A' + base: 'a' + shift, capslock: 'A' +} + +key S { + label: 'S' + base: 's' + shift, capslock: 'S' +} + +key D { + label: 'D' + base: 'd' + shift, capslock: 'D' +} + +key F { + label: 'F' + base: 'f' + shift, capslock: 'F' +} + +key G { + label: 'G' + base: 'g' + shift, capslock: 'G' +} + +key H { + label: 'H' + base: 'h' + shift, capslock: 'H' +} + +key J { + label: 'J' + base: 'j' + shift, capslock: 'J' +} + +key K { + label: 'K' + base: 'k' + shift, capslock: 'K' +} + +key L { + label: 'L' + base: 'l' + shift, capslock: 'L' +} + +key SEMICOLON { + label: '\u00d6' + base: '\u00f6' + shift, capslock: '\u00d6' +} + +key APOSTROPHE { + label: '\u00c4' + base: '\u00e4' + shift, capslock: '\u00c4' +} + +key BACKSLASH { + label: '#' + base: '#' + shift: '\'' +} + +### ROW 4 + +key PLUS { + label: '<' + base: '<' + shift: '>' + ralt: '|' +} + +key Y { + label: 'Y' + base: 'y' + shift, capslock: 'Y' +} + +key X { + label: 'X' + base: 'x' + shift, capslock: 'X' +} + +key C { + label: 'C' + base: 'c' + shift, capslock: 'C' +} + +key V { + label: 'V' + base: 'v' + shift, capslock: 'V' +} + +key B { + label: 'B' + base: 'b' + shift, capslock: 'B' +} + +key N { + label: 'N' + base: 'n' + shift, capslock: 'N' +} + +key M { + label: 'M' + base: 'm' + shift, capslock: 'M' + ralt: '\u00b5' +} + +key COMMA { + label: ',' + base: ',' + shift: ';' +} + +key PERIOD { + label: '.' + base: '.' + shift: ':' +} + +key MINUS { + label: '-' + base: '-' + shift: '_' +} diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index b9cc6485e5..d646756fc4 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -189,6 +189,10 @@ public: static void validateInputBufferUsage(const sp<GraphicBuffer>&); static void validateOutputBufferUsage(const sp<GraphicBuffer>&); + // Allows flinger to get the render engine thread id for power management with ADPF + // Returns the tid of the renderengine thread if it's threaded, and std::nullopt otherwise + virtual std::optional<pid_t> getRenderEngineTid() const { return std::nullopt; } + protected: RenderEngine() : RenderEngine(RenderEngineType::GLES) {} diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp index 08fc81468c..a7176d3279 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.cpp +++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp @@ -389,6 +389,20 @@ void RenderEngineThreaded::onActiveDisplaySizeChanged(ui::Size size) { mCondition.notify_one(); } +std::optional<pid_t> RenderEngineThreaded::getRenderEngineTid() const { + std::promise<pid_t> tidPromise; + std::future<pid_t> tidFuture = tidPromise.get_future(); + { + std::lock_guard lock(mThreadMutex); + mFunctionCalls.push([&tidPromise](renderengine::RenderEngine& instance) { + tidPromise.set_value(gettid()); + }); + } + + mCondition.notify_one(); + return std::make_optional(tidFuture.get()); +} + } // namespace threaded } // namespace renderengine } // namespace android diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h index 0159cfaece..1ba72ddf81 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.h +++ b/libs/renderengine/threaded/RenderEngineThreaded.h @@ -66,6 +66,7 @@ public: int getContextPriority() override; bool supportsBackgroundBlur() override; void onActiveDisplaySizeChanged(ui::Size size) override; + std::optional<pid_t> getRenderEngineTid() const override; protected: void mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, bool isRenderable) override; diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp index 8ac08fb70d..3fc99bb3fc 100644 --- a/libs/ui/Gralloc4.cpp +++ b/libs/ui/Gralloc4.cpp @@ -941,9 +941,10 @@ status_t Gralloc4Mapper::bufferDumpHelper(const BufferDump& bufferDump, std::ost } double allocationSizeKiB = static_cast<double>(allocationSize) / 1024; - *outDump << "+ name:" << name << ", id:" << bufferId << ", size:" << allocationSizeKiB - << "KiB, w/h:" << width << "x" << height << ", usage: 0x" << std::hex << usage - << std::dec << ", req fmt:" << static_cast<int32_t>(pixelFormatRequested) + *outDump << "+ name:" << name << ", id:" << bufferId << ", size:" << std::fixed + << allocationSizeKiB << "KiB, w/h:" << width << "x" << height << ", usage: 0x" + << std::hex << usage << std::dec + << ", req fmt:" << static_cast<int32_t>(pixelFormatRequested) << ", fourcc/mod:" << pixelFormatFourCC << "/" << pixelFormatModifier << ", dataspace: 0x" << std::hex << static_cast<uint32_t>(dataspace) << std::dec << ", compressed: "; diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index 8cdb706bcc..ec5832515c 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -24,6 +24,7 @@ package { cc_defaults { name: "inputflinger_defaults", + cpp_std: "c++20", cflags: [ "-Wall", "-Wextra", @@ -71,7 +72,6 @@ cc_defaults { "libstatssocket", "libutils", "libui", - "lib-platform-compat-native-api", "server_configurable_flags", ], static_libs: [ diff --git a/services/inputflinger/BlockingQueue.h b/services/inputflinger/BlockingQueue.h index b612ca77ce..8300e8a3da 100644 --- a/services/inputflinger/BlockingQueue.h +++ b/services/inputflinger/BlockingQueue.h @@ -71,8 +71,7 @@ public: void erase(const std::function<bool(const T&)>& lambda) { std::scoped_lock lock(mLock); - mQueue.erase(std::remove_if(mQueue.begin(), mQueue.end(), - [&lambda](const T& t) { return lambda(t); }), mQueue.end()); + std::erase_if(mQueue, [&lambda](const auto& t) { return lambda(t); }); } /** diff --git a/services/inputflinger/benchmarks/Android.bp b/services/inputflinger/benchmarks/Android.bp index 902bd0d7bb..75071d55ac 100644 --- a/services/inputflinger/benchmarks/Android.bp +++ b/services/inputflinger/benchmarks/Android.bp @@ -28,7 +28,6 @@ cc_benchmark { "libstatslog", "libui", "libutils", - "lib-platform-compat-native-api", ], static_libs: [ "libattestation", diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp index 4757d31d91..cdad9c93fd 100644 --- a/services/inputflinger/dispatcher/Android.bp +++ b/services/inputflinger/dispatcher/Android.bp @@ -66,7 +66,6 @@ cc_defaults { "libui", "libgui", "libutils", - "lib-platform-compat-native-api", "server_configurable_flags", ], static_libs: [ diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp index 936ecf9889..8046bbe25c 100644 --- a/services/inputflinger/dispatcher/Entry.cpp +++ b/services/inputflinger/dispatcher/Entry.cpp @@ -214,7 +214,7 @@ MotionEntry::MotionEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32 int32_t edgeFlags, float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition, nsecs_t downTime, uint32_t pointerCount, const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords, float xOffset, float yOffset) + const PointerCoords* pointerCoords) : EventEntry(id, Type::MOTION, eventTime, policyFlags), deviceId(deviceId), source(source), @@ -235,9 +235,6 @@ MotionEntry::MotionEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32 for (uint32_t i = 0; i < pointerCount; i++) { this->pointerProperties[i].copyFrom(pointerProperties[i]); this->pointerCoords[i].copyFrom(pointerCoords[i]); - if (xOffset || yOffset) { - this->pointerCoords[i].applyOffset(xOffset, yOffset); - } } } diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h index 477781a2ad..0f792967eb 100644 --- a/services/inputflinger/dispatcher/Entry.h +++ b/services/inputflinger/dispatcher/Entry.h @@ -184,8 +184,7 @@ struct MotionEntry : EventEntry { int32_t metaState, int32_t buttonState, MotionClassification classification, int32_t edgeFlags, float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition, nsecs_t downTime, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, - float xOffset, float yOffset); + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); std::string getDescription() const override; ~MotionEntry() override; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 6ff245081a..3f3c0db2c9 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -24,8 +24,6 @@ #include <android-base/stringprintf.h> #include <android/os/IInputConstants.h> #include <binder/Binder.h> -#include <binder/IServiceManager.h> -#include <com/android/internal/compat/IPlatformCompatNative.h> #include <ftl/enum.h> #include <gui/SurfaceComposerClient.h> #include <input/InputDevice.h> @@ -63,7 +61,6 @@ using android::os::BlockUntrustedTouchesMode; using android::os::IInputConstants; using android::os::InputEventInjectionResult; using android::os::InputEventInjectionSync; -using com::android::internal::compat::IPlatformCompatNative; namespace android::inputdispatcher { @@ -91,7 +88,6 @@ constexpr bool DEBUG_FOCUS = false; constexpr bool DEBUG_TOUCH_MODE = false; // Log debug messages about touch occlusion -// STOPSHIP(b/169067926): Set to false constexpr bool DEBUG_TOUCH_OCCLUSION = true; // Log debug messages about the app switch latency optimization. @@ -378,7 +374,7 @@ std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inputTarge motionEntry.yPrecision, motionEntry.xCursorPosition, motionEntry.yCursorPosition, motionEntry.downTime, motionEntry.pointerCount, motionEntry.pointerProperties, - pointerCoords.data(), 0 /* xOffset */, 0 /* yOffset */); + pointerCoords.data()); if (motionEntry.injectionState) { combinedMotionEntry->injectionState = motionEntry.injectionState; @@ -412,15 +408,6 @@ bool sharedPointersEqual(const std::shared_ptr<T>& lhs, const std::shared_ptr<T> return *lhs == *rhs; } -sp<IPlatformCompatNative> getCompatService() { - sp<IBinder> service(defaultServiceManager()->getService(String16("platform_compat_native"))); - if (service == nullptr) { - ALOGE("Failed to link to compat service"); - return nullptr; - } - return interface_cast<IPlatformCompatNative>(service); -} - KeyEvent createKeyEvent(const KeyEntry& entry) { KeyEvent event; event.initialize(entry.id, entry.deviceId, entry.source, entry.displayId, INVALID_HMAC, @@ -506,12 +493,6 @@ bool isConnectionResponsive(const Connection& connection) { return true; } -vec2 transformWithoutTranslation(const ui::Transform& transform, float x, float y) { - const vec2 transformedXy = transform.transform(x, y); - const vec2 transformedOrigin = transform.transform(0, 0); - return transformedXy - transformedOrigin; -} - // Returns true if the event type passed as argument represents a user activity. bool isUserActivityEvent(const EventEntry& eventEntry) { switch (eventEntry.type) { @@ -530,12 +511,14 @@ bool isUserActivityEvent(const EventEntry& eventEntry) { } // Returns true if the given window can accept pointer events at the given display location. -bool windowAcceptsTouchAt(const WindowInfo& windowInfo, int32_t displayId, int32_t x, int32_t y) { +bool windowAcceptsTouchAt(const WindowInfo& windowInfo, int32_t displayId, int32_t x, int32_t y, + bool isStylus) { if (windowInfo.displayId != displayId || !windowInfo.visible) { return false; } const auto flags = windowInfo.flags; - if (flags.test(WindowInfo::Flag::NOT_TOUCHABLE)) { + const bool windowCanInterceptTouch = isStylus && windowInfo.interceptsStylus(); + if (flags.test(WindowInfo::Flag::NOT_TOUCHABLE) && !windowCanInterceptTouch) { return false; } const bool isModalWindow = !flags.test(WindowInfo::Flag::NOT_FOCUSABLE) && @@ -546,6 +529,12 @@ bool windowAcceptsTouchAt(const WindowInfo& windowInfo, int32_t displayId, int32 return true; } +bool isPointerFromStylus(const MotionEntry& entry, int32_t pointerIndex) { + return isFromSource(entry.source, AINPUT_SOURCE_STYLUS) && + (entry.pointerProperties[pointerIndex].toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS || + entry.pointerProperties[pointerIndex].toolType == AMOTION_EVENT_TOOL_TYPE_ERASER); +} + } // namespace // --- InputDispatcher --- @@ -569,8 +558,7 @@ InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& polic mFocusedDisplayId(ADISPLAY_ID_DEFAULT), mWindowTokenWithPointerCapture(nullptr), mLatencyAggregator(), - mLatencyTracker(&mLatencyAggregator), - mCompatService(getCompatService()) { + mLatencyTracker(&mLatencyAggregator) { mLooper = new Looper(false); mReporter = createInputReporter(); @@ -939,8 +927,10 @@ bool InputDispatcher::shouldPruneInboundQueueLocked(const MotionEntry& motionEnt motionEntry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X)); int32_t y = static_cast<int32_t>( motionEntry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y)); + + const bool isStylus = isPointerFromStylus(motionEntry, 0 /*pointerIndex*/); sp<WindowInfoHandle> touchedWindowHandle = - findTouchedWindowAtLocked(displayId, x, y, nullptr); + findTouchedWindowAtLocked(displayId, x, y, nullptr, isStylus); if (touchedWindowHandle != nullptr && touchedWindowHandle->getApplicationToken() != mAwaitedFocusedApplication->getApplicationToken()) { @@ -1045,6 +1035,7 @@ void InputDispatcher::addRecentEventLocked(std::shared_ptr<EventEntry> entry) { sp<WindowInfoHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y, TouchState* touchState, + bool isStylus, bool addOutsideTargets, bool ignoreDragWindow) { if (addOutsideTargets && touchState == nullptr) { @@ -1058,7 +1049,7 @@ sp<WindowInfoHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayI } const WindowInfo& info = *windowHandle->getInfo(); - if (!info.isSpy() && windowAcceptsTouchAt(info, displayId, x, y)) { + if (!info.isSpy() && windowAcceptsTouchAt(info, displayId, x, y, isStylus)) { return windowHandle; } @@ -1070,16 +1061,15 @@ sp<WindowInfoHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayI return nullptr; } -std::vector<sp<WindowInfoHandle>> InputDispatcher::findTouchedSpyWindowsAtLocked(int32_t displayId, - int32_t x, - int32_t y) const { +std::vector<sp<WindowInfoHandle>> InputDispatcher::findTouchedSpyWindowsAtLocked( + int32_t displayId, int32_t x, int32_t y, bool isStylus) const { // Traverse windows from front to back and gather the touched spy windows. std::vector<sp<WindowInfoHandle>> spyWindows; const auto& windowHandles = getWindowHandlesLocked(displayId); for (const sp<WindowInfoHandle>& windowHandle : windowHandles) { const WindowInfo& info = *windowHandle->getInfo(); - if (!windowAcceptsTouchAt(info, displayId, x, y)) { + if (!windowAcceptsTouchAt(info, displayId, x, y, isStylus)) { continue; } if (!info.isSpy()) { @@ -2062,8 +2052,9 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( y = int32_t(entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y)); } const bool isDown = maskedAction == AMOTION_EVENT_ACTION_DOWN; + const bool isStylus = isPointerFromStylus(entry, pointerIndex); newTouchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y, &tempTouchState, - isDown /*addOutsideTargets*/); + isStylus, isDown /*addOutsideTargets*/); // Handle the case where we did not find a window. if (newTouchedWindowHandle == nullptr) { @@ -2100,7 +2091,7 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( } std::vector<sp<WindowInfoHandle>> newTouchedWindows = - findTouchedSpyWindowsAtLocked(displayId, x, y); + findTouchedSpyWindowsAtLocked(displayId, x, y, isStylus); if (newTouchedWindowHandle != nullptr) { // Process the foreground window first so that it is the first to receive the event. newTouchedWindows.insert(newTouchedWindows.begin(), newTouchedWindowHandle); @@ -2213,9 +2204,11 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( const int32_t x = int32_t(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X)); const int32_t y = int32_t(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y)); + const bool isStylus = isPointerFromStylus(entry, 0 /*pointerIndex*/); sp<WindowInfoHandle> oldTouchedWindowHandle = tempTouchState.getFirstForegroundWindowHandle(); - newTouchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y, &tempTouchState); + newTouchedWindowHandle = + findTouchedWindowAtLocked(displayId, x, y, &tempTouchState, isStylus); // Drop touch events if requested by input feature if (newTouchedWindowHandle != nullptr && @@ -2477,8 +2470,12 @@ Failed: } void InputDispatcher::finishDragAndDrop(int32_t displayId, float x, float y) { + // Prevent stylus interceptor windows from affecting drag and drop behavior for now, until we + // have an explicit reason to support it. + constexpr bool isStylus = false; + const sp<WindowInfoHandle> dropWindow = - findTouchedWindowAtLocked(displayId, x, y, nullptr /*touchState*/, + findTouchedWindowAtLocked(displayId, x, y, nullptr /*touchState*/, isStylus, false /*addOutsideTargets*/, true /*ignoreDragWindow*/); if (dropWindow) { vec2 local = dropWindow->getInfo()->transform.transform(x, y); @@ -2511,8 +2508,12 @@ void InputDispatcher::addDragEventLocked(const MotionEntry& entry) { return; } + // Prevent stylus interceptor windows from affecting drag and drop behavior for now, until + // we have an explicit reason to support it. + constexpr bool isStylus = false; + const sp<WindowInfoHandle> hoverWindowHandle = - findTouchedWindowAtLocked(entry.displayId, x, y, nullptr /*touchState*/, + findTouchedWindowAtLocked(entry.displayId, x, y, nullptr /*touchState*/, isStylus, false /*addOutsideTargets*/, true /*ignoreDragWindow*/); // enqueue drag exit if needed. if (hoverWindowHandle != mDragState->dragHoverWindowHandle && @@ -3815,7 +3816,7 @@ std::unique_ptr<MotionEntry> InputDispatcher::splitMotionEvent( originalMotionEntry.xCursorPosition, originalMotionEntry.yCursorPosition, originalMotionEntry.downTime, splitPointerCount, - splitPointerProperties, splitPointerCoords, 0, 0); + splitPointerProperties, splitPointerCoords); if (originalMotionEntry.injectionState) { splitMotionEntry->injectionState = originalMotionEntry.injectionState; @@ -4041,7 +4042,7 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { args->xPrecision, args->yPrecision, args->xCursorPosition, args->yCursorPosition, args->downTime, args->pointerCount, - args->pointerProperties, args->pointerCoords, 0, 0); + args->pointerProperties, args->pointerCoords); if (args->id != android::os::IInputConstants::INVALID_INPUT_EVENT_ID && IdGenerator::getSource(args->id) == IdGenerator::Source::INPUT_READER && @@ -4271,10 +4272,8 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( motionEvent.getRawXCursorPosition(), motionEvent.getRawYCursorPosition(), motionEvent.getDownTime(), uint32_t(pointerCount), - pointerProperties, samplePointerCoords, - motionEvent.getXOffset(), - motionEvent.getYOffset()); - transformMotionEntryForInjectionLocked(*injectedEntry); + pointerProperties, samplePointerCoords); + transformMotionEntryForInjectionLocked(*injectedEntry, motionEvent.getTransform()); injectedEntries.push(std::move(injectedEntry)); for (size_t i = motionEvent.getHistorySize(); i > 0; i--) { sampleEventTimes += 1; @@ -4293,9 +4292,9 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( motionEvent.getRawYCursorPosition(), motionEvent.getDownTime(), uint32_t(pointerCount), pointerProperties, - samplePointerCoords, motionEvent.getXOffset(), - motionEvent.getYOffset()); - transformMotionEntryForInjectionLocked(*nextInjectedEntry); + samplePointerCoords); + transformMotionEntryForInjectionLocked(*nextInjectedEntry, + motionEvent.getTransform()); injectedEntries.push(std::move(nextInjectedEntry)); } break; @@ -4459,35 +4458,28 @@ void InputDispatcher::setInjectionResult(EventEntry& entry, } } -void InputDispatcher::transformMotionEntryForInjectionLocked(MotionEntry& entry) const { - const bool isRelativeMouseEvent = isFromSource(entry.source, AINPUT_SOURCE_MOUSE_RELATIVE); - if (!isRelativeMouseEvent && !isFromSource(entry.source, AINPUT_SOURCE_CLASS_POINTER)) { - return; - } - +void InputDispatcher::transformMotionEntryForInjectionLocked( + MotionEntry& entry, const ui::Transform& injectedTransform) const { // Input injection works in the logical display coordinate space, but the input pipeline works // display space, so we need to transform the injected events accordingly. const auto it = mDisplayInfos.find(entry.displayId); if (it == mDisplayInfos.end()) return; - const auto& transformToDisplay = it->second.transform.inverse(); + const auto& transformToDisplay = it->second.transform.inverse() * injectedTransform; for (uint32_t i = 0; i < entry.pointerCount; i++) { PointerCoords& pc = entry.pointerCoords[i]; - const auto xy = isRelativeMouseEvent - ? transformWithoutTranslation(transformToDisplay, pc.getX(), pc.getY()) - : transformToDisplay.transform(pc.getXYValue()); - pc.setAxisValue(AMOTION_EVENT_AXIS_X, xy.x); - pc.setAxisValue(AMOTION_EVENT_AXIS_Y, xy.y); + // Make a copy of the injected coords. We cannot change them in place because some of them + // are interdependent (for example, X coordinate might depend on the Y coordinate). + PointerCoords injectedCoords = entry.pointerCoords[i]; - // Axes with relative values never represent points on a screen, so they should never have - // translation applied. If a device does not report relative values, these values are always - // 0, and will remain unaffected by the following operation. - const auto rel = - transformWithoutTranslation(transformToDisplay, - pc.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), - pc.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)); - pc.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, rel.x); - pc.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, rel.y); + BitSet64 bits(injectedCoords.bits); + while (!bits.isEmpty()) { + const auto axis = static_cast<int32_t>(bits.clearFirstMarkedBit()); + const float value = + MotionEvent::calculateTransformedAxisValue(axis, entry.source, + transformToDisplay, injectedCoords); + pc.setAxisValue(axis, value); + } } } @@ -4685,15 +4677,27 @@ void InputDispatcher::setInputWindowsLocked( ALOGD("setInputWindows displayId=%" PRId32 " %s", displayId, windowList.c_str()); } - // Ensure all tokens are null if the window has feature NO_INPUT_CHANNEL + // Check preconditions for new input windows for (const sp<WindowInfoHandle>& window : windowInfoHandles) { - const bool noInputWindow = - window->getInfo()->inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL); + const WindowInfo& info = *window->getInfo(); + + // Ensure all tokens are null if the window has feature NO_INPUT_CHANNEL + const bool noInputWindow = info.inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL); if (noInputWindow && window->getToken() != nullptr) { ALOGE("%s has feature NO_INPUT_WINDOW, but a non-null token. Clearing", window->getName().c_str()); window->releaseChannel(); } + + // Ensure all spy windows are trusted overlays + LOG_ALWAYS_FATAL_IF(info.isSpy() && !info.trustedOverlay, + "%s has feature SPY, but is not a trusted overlay.", + window->getName().c_str()); + + // Ensure all stylus interceptors are trusted overlays + LOG_ALWAYS_FATAL_IF(info.interceptsStylus() && !info.trustedOverlay, + "%s has feature INTERCEPTS_STYLUS, but is not a trusted overlay.", + window->getName().c_str()); } // Copy old handles for release if they are no longer present. @@ -4795,18 +4799,6 @@ void InputDispatcher::setInputWindowsLocked( ALOGD("Window went away: %s", oldWindowHandle->getName().c_str()); } oldWindowHandle->releaseChannel(); - // To avoid making too many calls into the compat framework, only - // check for window flags when windows are going away. - // TODO(b/157929241) : delete this. This is only needed temporarily - // in order to gather some data about the flag usage - if (oldWindowHandle->getInfo()->flags.test(WindowInfo::Flag::SLIPPERY)) { - ALOGW("%s has FLAG_SLIPPERY. Please report this in b/157929241", - oldWindowHandle->getName().c_str()); - if (mCompatService != nullptr) { - mCompatService->reportChangeByUid(IInputConstants::BLOCK_FLAG_SLIPPERY, - oldWindowHandle->getInfo()->ownerUid); - } - } } } } diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index fb9c81b4f6..cbb7bad5ea 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -36,7 +36,6 @@ #include "TouchedWindow.h" #include <attestation/HmacKeyManager.h> -#include <com/android/internal/compat/IPlatformCompatNative.h> #include <gui/InputApplication.h> #include <gui/WindowInfo.h> #include <input/Input.h> @@ -234,16 +233,12 @@ private: // to transfer focus to a new application. std::shared_ptr<EventEntry> mNextUnblockedEvent GUARDED_BY(mLock); - sp<android::gui::WindowInfoHandle> findTouchedWindowAtLocked(int32_t displayId, int32_t x, - int32_t y, TouchState* touchState, - bool addOutsideTargets = false, - bool ignoreDragWindow = false) - REQUIRES(mLock); + sp<android::gui::WindowInfoHandle> findTouchedWindowAtLocked( + int32_t displayId, int32_t x, int32_t y, TouchState* touchState, bool isStylus = false, + bool addOutsideTargets = false, bool ignoreDragWindow = false) REQUIRES(mLock); - std::vector<sp<android::gui::WindowInfoHandle>> findTouchedSpyWindowsAtLocked(int32_t displayId, - int32_t x, - int32_t y) const - REQUIRES(mLock); + std::vector<sp<android::gui::WindowInfoHandle>> findTouchedSpyWindowsAtLocked( + int32_t displayId, int32_t x, int32_t y, bool isStylus) const REQUIRES(mLock); sp<Connection> getConnectionLocked(const sp<IBinder>& inputConnectionToken) const REQUIRES(mLock); @@ -287,7 +282,9 @@ private: bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid); void setInjectionResult(EventEntry& entry, android::os::InputEventInjectionResult injectionResult); - void transformMotionEntryForInjectionLocked(MotionEntry&) const REQUIRES(mLock); + void transformMotionEntryForInjectionLocked(MotionEntry&, + const ui::Transform& injectedTransform) const + REQUIRES(mLock); std::condition_variable mInjectionSyncFinished; void incrementPendingForegroundDispatches(EventEntry& entry); @@ -681,7 +678,6 @@ private: void traceWaitQueueLength(const Connection& connection); sp<InputReporterInterface> mReporter; - sp<com::android::internal::compat::IPlatformCompatNative> mCompatService; }; } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp index 3bb0bc995c..ad3c6159ef 100644 --- a/services/inputflinger/dispatcher/InputState.cpp +++ b/services/inputflinger/dispatcher/InputState.cpp @@ -296,8 +296,7 @@ std::vector<std::unique_ptr<EventEntry>> InputState::synthesizeCancelationEvents memento.yPrecision, memento.xCursorPosition, memento.yCursorPosition, memento.downTime, memento.pointerCount, memento.pointerProperties, - memento.pointerCoords, 0 /*xOffset*/, - 0 /*yOffset*/)); + memento.pointerCoords)); } } return events; @@ -349,8 +348,7 @@ std::vector<std::unique_ptr<EventEntry>> InputState::synthesizePointerDownEvents AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision, memento.yPrecision, memento.xCursorPosition, memento.yCursorPosition, memento.downTime, - pointerCount, pointerProperties, pointerCoords, - 0 /*xOffset*/, 0 /*yOffset*/)); + pointerCount, pointerProperties, pointerCoords)); } memento.firstNewPointerIdx = INVALID_POINTER_INDEX; diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp index d624e99acf..08c7826045 100644 --- a/services/inputflinger/dispatcher/TouchState.cpp +++ b/services/inputflinger/dispatcher/TouchState.cpp @@ -106,10 +106,8 @@ void TouchState::filterNonAsIsTouchWindows() { } void TouchState::filterWindowsExcept(const sp<IBinder>& token) { - auto it = std::remove_if(windows.begin(), windows.end(), [&token](const TouchedWindow& w) { - return w.windowHandle->getToken() != token; - }); - windows.erase(it, windows.end()); + std::erase_if(windows, + [&token](const TouchedWindow& w) { return w.windowHandle->getToken() != token; }); } sp<WindowInfoHandle> TouchState::getFirstForegroundWindowHandle() const { diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp index d10f8b6605..09a62f35cd 100644 --- a/services/inputflinger/reader/EventHub.cpp +++ b/services/inputflinger/reader/EventHub.cpp @@ -1262,12 +1262,11 @@ const std::shared_ptr<KeyCharacterMap> EventHub::getKeyCharacterMap(int32_t devi bool EventHub::setKeyboardLayoutOverlay(int32_t deviceId, std::shared_ptr<KeyCharacterMap> map) { std::scoped_lock _l(mLock); Device* device = getDeviceLocked(deviceId); - if (device != nullptr && map != nullptr && device->keyMap.keyCharacterMap != nullptr) { - device->keyMap.keyCharacterMap->combine(*map); - device->keyMap.keyCharacterMapFile = device->keyMap.keyCharacterMap->getLoadFileName(); - return true; + if (device == nullptr || map == nullptr || device->keyMap.keyCharacterMap == nullptr) { + return false; } - return false; + device->keyMap.keyCharacterMap->combine(*map); + return true; } static std::string generateDescriptor(InputDeviceIdentifier& identifier) { @@ -2344,13 +2343,10 @@ void EventHub::closeVideoDeviceByPathLocked(const std::string& devicePath) { return; } } - mUnattachedVideoDevices - .erase(std::remove_if(mUnattachedVideoDevices.begin(), mUnattachedVideoDevices.end(), - [&devicePath]( - const std::unique_ptr<TouchVideoDevice>& videoDevice) { - return videoDevice->getPath() == devicePath; - }), - mUnattachedVideoDevices.end()); + std::erase_if(mUnattachedVideoDevices, + [&devicePath](const std::unique_ptr<TouchVideoDevice>& videoDevice) { + return videoDevice->getPath() == devicePath; + }); } void EventHub::closeAllDevicesLocked() { diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp index 7704a84b5b..564db56ca9 100644 --- a/services/inputflinger/reader/InputReader.cpp +++ b/services/inputflinger/reader/InputReader.cpp @@ -237,9 +237,7 @@ void InputReader::removeDeviceLocked(nsecs_t when, int32_t eventHubId) { auto mapIt = mDeviceToEventHubIdsMap.find(device); if (mapIt != mDeviceToEventHubIdsMap.end()) { std::vector<int32_t>& eventHubIds = mapIt->second; - eventHubIds.erase(std::remove_if(eventHubIds.begin(), eventHubIds.end(), - [eventHubId](int32_t eId) { return eId == eventHubId; }), - eventHubIds.end()); + std::erase_if(eventHubIds, [eventHubId](int32_t eId) { return eId == eventHubId; }); if (eventHubIds.size() == 0) { mDeviceToEventHubIdsMap.erase(mapIt); } diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h index f1c0e5a570..d83d74df7b 100644 --- a/services/inputflinger/reader/mapper/InputMapper.h +++ b/services/inputflinger/reader/mapper/InputMapper.h @@ -45,7 +45,7 @@ public: inline int32_t getDeviceId() { return mDeviceContext.getId(); } inline InputDeviceContext& getDeviceContext() { return mDeviceContext; } - inline const std::string getDeviceName() { return mDeviceContext.getName(); } + inline const std::string getDeviceName() const { return mDeviceContext.getName(); } inline InputReaderContext* getContext() { return mDeviceContext.getContext(); } inline InputReaderPolicyInterface* getPolicy() { return getContext()->getPolicy(); } inline InputListenerInterface& getListener() { return getContext()->getListener(); } diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp index 6bdb121336..ad11b05576 100644 --- a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp +++ b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp @@ -32,8 +32,7 @@ uint32_t JoystickInputMapper::getSources() { void JoystickInputMapper::populateDeviceInfo(InputDeviceInfo* info) { InputMapper::populateDeviceInfo(info); - for (std::pair<const int32_t, Axis>& pair : mAxes) { - const Axis& axis = pair.second; + for (const auto& [_, axis] : mAxes) { addMotionRange(axis.axisInfo.axis, axis, info); if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index 6f49f31aa8..0a5de279dc 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -609,6 +609,270 @@ std::optional<DisplayViewport> TouchInputMapper::findViewport() { return std::make_optional(newViewport); } +int32_t TouchInputMapper::clampResolution(const char* axisName, int32_t resolution) const { + if (resolution < 0) { + ALOGE("Invalid %s resolution %" PRId32 " for device %s", axisName, resolution, + getDeviceName().c_str()); + return 0; + } + return resolution; +} + +void TouchInputMapper::initializeSizeRanges() { + if (mCalibration.sizeCalibration == Calibration::SizeCalibration::NONE) { + mSizeScale = 0.0f; + return; + } + + // Size of diagonal axis. + const float diagonalSize = hypotf(mDisplayWidth, mDisplayHeight); + + // Size factors. + if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.touchMajor.maxValue != 0) { + mSizeScale = 1.0f / mRawPointerAxes.touchMajor.maxValue; + } else if (mRawPointerAxes.toolMajor.valid && mRawPointerAxes.toolMajor.maxValue != 0) { + mSizeScale = 1.0f / mRawPointerAxes.toolMajor.maxValue; + } else { + mSizeScale = 0.0f; + } + + mOrientedRanges.haveTouchSize = true; + mOrientedRanges.haveToolSize = true; + mOrientedRanges.haveSize = true; + + mOrientedRanges.touchMajor.axis = AMOTION_EVENT_AXIS_TOUCH_MAJOR; + mOrientedRanges.touchMajor.source = mSource; + mOrientedRanges.touchMajor.min = 0; + mOrientedRanges.touchMajor.max = diagonalSize; + mOrientedRanges.touchMajor.flat = 0; + mOrientedRanges.touchMajor.fuzz = 0; + mOrientedRanges.touchMajor.resolution = 0; + if (mRawPointerAxes.touchMajor.valid) { + mRawPointerAxes.touchMajor.resolution = + clampResolution("touchMajor", mRawPointerAxes.touchMajor.resolution); + mOrientedRanges.touchMajor.resolution = mRawPointerAxes.touchMajor.resolution; + } + + mOrientedRanges.touchMinor = mOrientedRanges.touchMajor; + mOrientedRanges.touchMinor.axis = AMOTION_EVENT_AXIS_TOUCH_MINOR; + if (mRawPointerAxes.touchMinor.valid) { + mRawPointerAxes.touchMinor.resolution = + clampResolution("touchMinor", mRawPointerAxes.touchMinor.resolution); + mOrientedRanges.touchMinor.resolution = mRawPointerAxes.touchMinor.resolution; + } + + mOrientedRanges.toolMajor.axis = AMOTION_EVENT_AXIS_TOOL_MAJOR; + mOrientedRanges.toolMajor.source = mSource; + mOrientedRanges.toolMajor.min = 0; + mOrientedRanges.toolMajor.max = diagonalSize; + mOrientedRanges.toolMajor.flat = 0; + mOrientedRanges.toolMajor.fuzz = 0; + mOrientedRanges.toolMajor.resolution = 0; + if (mRawPointerAxes.toolMajor.valid) { + mRawPointerAxes.toolMajor.resolution = + clampResolution("toolMajor", mRawPointerAxes.toolMajor.resolution); + mOrientedRanges.toolMajor.resolution = mRawPointerAxes.toolMajor.resolution; + } + + mOrientedRanges.toolMinor = mOrientedRanges.toolMajor; + mOrientedRanges.toolMinor.axis = AMOTION_EVENT_AXIS_TOOL_MINOR; + if (mRawPointerAxes.toolMinor.valid) { + mRawPointerAxes.toolMinor.resolution = + clampResolution("toolMinor", mRawPointerAxes.toolMinor.resolution); + mOrientedRanges.toolMinor.resolution = mRawPointerAxes.toolMinor.resolution; + } + + if (mCalibration.sizeCalibration == Calibration::SizeCalibration::GEOMETRIC) { + mOrientedRanges.touchMajor.resolution *= mGeometricScale; + mOrientedRanges.touchMinor.resolution *= mGeometricScale; + mOrientedRanges.toolMajor.resolution *= mGeometricScale; + mOrientedRanges.toolMinor.resolution *= mGeometricScale; + } else { + // Support for other calibrations can be added here. + ALOGW("%s calibration is not supported for size ranges at the moment. " + "Using raw resolution instead", + ftl::enum_string(mCalibration.sizeCalibration).c_str()); + } + + mOrientedRanges.size.axis = AMOTION_EVENT_AXIS_SIZE; + mOrientedRanges.size.source = mSource; + mOrientedRanges.size.min = 0; + mOrientedRanges.size.max = 1.0; + mOrientedRanges.size.flat = 0; + mOrientedRanges.size.fuzz = 0; + mOrientedRanges.size.resolution = 0; +} + +void TouchInputMapper::initializeOrientedRanges() { + // Configure X and Y factors. + mXScale = float(mDisplayWidth) / mRawPointerAxes.getRawWidth(); + mYScale = float(mDisplayHeight) / mRawPointerAxes.getRawHeight(); + mXPrecision = 1.0f / mXScale; + mYPrecision = 1.0f / mYScale; + + mOrientedRanges.x.axis = AMOTION_EVENT_AXIS_X; + mOrientedRanges.x.source = mSource; + mOrientedRanges.y.axis = AMOTION_EVENT_AXIS_Y; + mOrientedRanges.y.source = mSource; + + // Scale factor for terms that are not oriented in a particular axis. + // If the pixels are square then xScale == yScale otherwise we fake it + // by choosing an average. + mGeometricScale = avg(mXScale, mYScale); + + initializeSizeRanges(); + + // Pressure factors. + mPressureScale = 0; + float pressureMax = 1.0; + if (mCalibration.pressureCalibration == Calibration::PressureCalibration::PHYSICAL || + mCalibration.pressureCalibration == Calibration::PressureCalibration::AMPLITUDE) { + if (mCalibration.havePressureScale) { + mPressureScale = mCalibration.pressureScale; + pressureMax = mPressureScale * mRawPointerAxes.pressure.maxValue; + } else if (mRawPointerAxes.pressure.valid && mRawPointerAxes.pressure.maxValue != 0) { + mPressureScale = 1.0f / mRawPointerAxes.pressure.maxValue; + } + } + + mOrientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE; + mOrientedRanges.pressure.source = mSource; + mOrientedRanges.pressure.min = 0; + mOrientedRanges.pressure.max = pressureMax; + mOrientedRanges.pressure.flat = 0; + mOrientedRanges.pressure.fuzz = 0; + mOrientedRanges.pressure.resolution = 0; + + // Tilt + mTiltXCenter = 0; + mTiltXScale = 0; + mTiltYCenter = 0; + mTiltYScale = 0; + mHaveTilt = mRawPointerAxes.tiltX.valid && mRawPointerAxes.tiltY.valid; + if (mHaveTilt) { + mTiltXCenter = avg(mRawPointerAxes.tiltX.minValue, mRawPointerAxes.tiltX.maxValue); + mTiltYCenter = avg(mRawPointerAxes.tiltY.minValue, mRawPointerAxes.tiltY.maxValue); + mTiltXScale = M_PI / 180; + mTiltYScale = M_PI / 180; + + if (mRawPointerAxes.tiltX.resolution) { + mTiltXScale = 1.0 / mRawPointerAxes.tiltX.resolution; + } + if (mRawPointerAxes.tiltY.resolution) { + mTiltYScale = 1.0 / mRawPointerAxes.tiltY.resolution; + } + + mOrientedRanges.haveTilt = true; + + mOrientedRanges.tilt.axis = AMOTION_EVENT_AXIS_TILT; + mOrientedRanges.tilt.source = mSource; + mOrientedRanges.tilt.min = 0; + mOrientedRanges.tilt.max = M_PI_2; + mOrientedRanges.tilt.flat = 0; + mOrientedRanges.tilt.fuzz = 0; + mOrientedRanges.tilt.resolution = 0; + } + + // Orientation + mOrientationScale = 0; + if (mHaveTilt) { + mOrientedRanges.haveOrientation = true; + + mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION; + mOrientedRanges.orientation.source = mSource; + mOrientedRanges.orientation.min = -M_PI; + mOrientedRanges.orientation.max = M_PI; + mOrientedRanges.orientation.flat = 0; + mOrientedRanges.orientation.fuzz = 0; + mOrientedRanges.orientation.resolution = 0; + } else if (mCalibration.orientationCalibration != Calibration::OrientationCalibration::NONE) { + if (mCalibration.orientationCalibration == + Calibration::OrientationCalibration::INTERPOLATED) { + if (mRawPointerAxes.orientation.valid) { + if (mRawPointerAxes.orientation.maxValue > 0) { + mOrientationScale = M_PI_2 / mRawPointerAxes.orientation.maxValue; + } else if (mRawPointerAxes.orientation.minValue < 0) { + mOrientationScale = -M_PI_2 / mRawPointerAxes.orientation.minValue; + } else { + mOrientationScale = 0; + } + } + } + + mOrientedRanges.haveOrientation = true; + + mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION; + mOrientedRanges.orientation.source = mSource; + mOrientedRanges.orientation.min = -M_PI_2; + mOrientedRanges.orientation.max = M_PI_2; + mOrientedRanges.orientation.flat = 0; + mOrientedRanges.orientation.fuzz = 0; + mOrientedRanges.orientation.resolution = 0; + } + + // Distance + mDistanceScale = 0; + if (mCalibration.distanceCalibration != Calibration::DistanceCalibration::NONE) { + if (mCalibration.distanceCalibration == Calibration::DistanceCalibration::SCALED) { + if (mCalibration.haveDistanceScale) { + mDistanceScale = mCalibration.distanceScale; + } else { + mDistanceScale = 1.0f; + } + } + + mOrientedRanges.haveDistance = true; + + mOrientedRanges.distance.axis = AMOTION_EVENT_AXIS_DISTANCE; + mOrientedRanges.distance.source = mSource; + mOrientedRanges.distance.min = mRawPointerAxes.distance.minValue * mDistanceScale; + mOrientedRanges.distance.max = mRawPointerAxes.distance.maxValue * mDistanceScale; + mOrientedRanges.distance.flat = 0; + mOrientedRanges.distance.fuzz = mRawPointerAxes.distance.fuzz * mDistanceScale; + mOrientedRanges.distance.resolution = 0; + } + + // Compute oriented precision, scales and ranges. + // Note that the maximum value reported is an inclusive maximum value so it is one + // unit less than the total width or height of the display. + switch (mInputDeviceOrientation) { + case DISPLAY_ORIENTATION_90: + case DISPLAY_ORIENTATION_270: + mOrientedXPrecision = mYPrecision; + mOrientedYPrecision = mXPrecision; + + mOrientedRanges.x.min = 0; + mOrientedRanges.x.max = mDisplayHeight - 1; + mOrientedRanges.x.flat = 0; + mOrientedRanges.x.fuzz = 0; + mOrientedRanges.x.resolution = mRawPointerAxes.y.resolution * mYScale; + + mOrientedRanges.y.min = 0; + mOrientedRanges.y.max = mDisplayWidth - 1; + mOrientedRanges.y.flat = 0; + mOrientedRanges.y.fuzz = 0; + mOrientedRanges.y.resolution = mRawPointerAxes.x.resolution * mXScale; + break; + + default: + mOrientedXPrecision = mXPrecision; + mOrientedYPrecision = mYPrecision; + + mOrientedRanges.x.min = 0; + mOrientedRanges.x.max = mDisplayWidth - 1; + mOrientedRanges.x.flat = 0; + mOrientedRanges.x.fuzz = 0; + mOrientedRanges.x.resolution = mRawPointerAxes.x.resolution * mXScale; + + mOrientedRanges.y.min = 0; + mOrientedRanges.y.max = mDisplayHeight - 1; + mOrientedRanges.y.flat = 0; + mOrientedRanges.y.fuzz = 0; + mOrientedRanges.y.resolution = mRawPointerAxes.y.resolution * mYScale; + break; + } +} + void TouchInputMapper::configureInputDevice(nsecs_t when, bool* outResetNeeded) { DeviceMode oldDeviceMode = mDeviceMode; @@ -795,224 +1059,9 @@ void TouchInputMapper::configureInputDevice(nsecs_t when, bool* outResetNeeded) getDeviceId(), getDeviceName().c_str(), mDisplayWidth, mDisplayHeight, mInputDeviceOrientation, mDeviceMode, mViewport.displayId); - // Configure X and Y factors. - mXScale = float(mDisplayWidth) / rawWidth; - mYScale = float(mDisplayHeight) / rawHeight; - mXPrecision = 1.0f / mXScale; - mYPrecision = 1.0f / mYScale; - - mOrientedRanges.x.axis = AMOTION_EVENT_AXIS_X; - mOrientedRanges.x.source = mSource; - mOrientedRanges.y.axis = AMOTION_EVENT_AXIS_Y; - mOrientedRanges.y.source = mSource; - configureVirtualKeys(); - // Scale factor for terms that are not oriented in a particular axis. - // If the pixels are square then xScale == yScale otherwise we fake it - // by choosing an average. - mGeometricScale = avg(mXScale, mYScale); - - // Size of diagonal axis. - float diagonalSize = hypotf(mDisplayWidth, mDisplayHeight); - - // Size factors. - if (mCalibration.sizeCalibration != Calibration::SizeCalibration::NONE) { - if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.touchMajor.maxValue != 0) { - mSizeScale = 1.0f / mRawPointerAxes.touchMajor.maxValue; - } else if (mRawPointerAxes.toolMajor.valid && mRawPointerAxes.toolMajor.maxValue != 0) { - mSizeScale = 1.0f / mRawPointerAxes.toolMajor.maxValue; - } else { - mSizeScale = 0.0f; - } - - mOrientedRanges.haveTouchSize = true; - mOrientedRanges.haveToolSize = true; - mOrientedRanges.haveSize = true; - - mOrientedRanges.touchMajor.axis = AMOTION_EVENT_AXIS_TOUCH_MAJOR; - mOrientedRanges.touchMajor.source = mSource; - mOrientedRanges.touchMajor.min = 0; - mOrientedRanges.touchMajor.max = diagonalSize; - mOrientedRanges.touchMajor.flat = 0; - mOrientedRanges.touchMajor.fuzz = 0; - mOrientedRanges.touchMajor.resolution = 0; - - mOrientedRanges.touchMinor = mOrientedRanges.touchMajor; - mOrientedRanges.touchMinor.axis = AMOTION_EVENT_AXIS_TOUCH_MINOR; - - mOrientedRanges.toolMajor.axis = AMOTION_EVENT_AXIS_TOOL_MAJOR; - mOrientedRanges.toolMajor.source = mSource; - mOrientedRanges.toolMajor.min = 0; - mOrientedRanges.toolMajor.max = diagonalSize; - mOrientedRanges.toolMajor.flat = 0; - mOrientedRanges.toolMajor.fuzz = 0; - mOrientedRanges.toolMajor.resolution = 0; - - mOrientedRanges.toolMinor = mOrientedRanges.toolMajor; - mOrientedRanges.toolMinor.axis = AMOTION_EVENT_AXIS_TOOL_MINOR; - - mOrientedRanges.size.axis = AMOTION_EVENT_AXIS_SIZE; - mOrientedRanges.size.source = mSource; - mOrientedRanges.size.min = 0; - mOrientedRanges.size.max = 1.0; - mOrientedRanges.size.flat = 0; - mOrientedRanges.size.fuzz = 0; - mOrientedRanges.size.resolution = 0; - } else { - mSizeScale = 0.0f; - } - - // Pressure factors. - mPressureScale = 0; - float pressureMax = 1.0; - if (mCalibration.pressureCalibration == Calibration::PressureCalibration::PHYSICAL || - mCalibration.pressureCalibration == Calibration::PressureCalibration::AMPLITUDE) { - if (mCalibration.havePressureScale) { - mPressureScale = mCalibration.pressureScale; - pressureMax = mPressureScale * mRawPointerAxes.pressure.maxValue; - } else if (mRawPointerAxes.pressure.valid && mRawPointerAxes.pressure.maxValue != 0) { - mPressureScale = 1.0f / mRawPointerAxes.pressure.maxValue; - } - } - - mOrientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE; - mOrientedRanges.pressure.source = mSource; - mOrientedRanges.pressure.min = 0; - mOrientedRanges.pressure.max = pressureMax; - mOrientedRanges.pressure.flat = 0; - mOrientedRanges.pressure.fuzz = 0; - mOrientedRanges.pressure.resolution = 0; - - // Tilt - mTiltXCenter = 0; - mTiltXScale = 0; - mTiltYCenter = 0; - mTiltYScale = 0; - mHaveTilt = mRawPointerAxes.tiltX.valid && mRawPointerAxes.tiltY.valid; - if (mHaveTilt) { - mTiltXCenter = avg(mRawPointerAxes.tiltX.minValue, mRawPointerAxes.tiltX.maxValue); - mTiltYCenter = avg(mRawPointerAxes.tiltY.minValue, mRawPointerAxes.tiltY.maxValue); - mTiltXScale = M_PI / 180; - mTiltYScale = M_PI / 180; - - if (mRawPointerAxes.tiltX.resolution) { - mTiltXScale = 1.0 / mRawPointerAxes.tiltX.resolution; - } - if (mRawPointerAxes.tiltY.resolution) { - mTiltYScale = 1.0 / mRawPointerAxes.tiltY.resolution; - } - - mOrientedRanges.haveTilt = true; - - mOrientedRanges.tilt.axis = AMOTION_EVENT_AXIS_TILT; - mOrientedRanges.tilt.source = mSource; - mOrientedRanges.tilt.min = 0; - mOrientedRanges.tilt.max = M_PI_2; - mOrientedRanges.tilt.flat = 0; - mOrientedRanges.tilt.fuzz = 0; - mOrientedRanges.tilt.resolution = 0; - } - - // Orientation - mOrientationScale = 0; - if (mHaveTilt) { - mOrientedRanges.haveOrientation = true; - - mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION; - mOrientedRanges.orientation.source = mSource; - mOrientedRanges.orientation.min = -M_PI; - mOrientedRanges.orientation.max = M_PI; - mOrientedRanges.orientation.flat = 0; - mOrientedRanges.orientation.fuzz = 0; - mOrientedRanges.orientation.resolution = 0; - } else if (mCalibration.orientationCalibration != - Calibration::OrientationCalibration::NONE) { - if (mCalibration.orientationCalibration == - Calibration::OrientationCalibration::INTERPOLATED) { - if (mRawPointerAxes.orientation.valid) { - if (mRawPointerAxes.orientation.maxValue > 0) { - mOrientationScale = M_PI_2 / mRawPointerAxes.orientation.maxValue; - } else if (mRawPointerAxes.orientation.minValue < 0) { - mOrientationScale = -M_PI_2 / mRawPointerAxes.orientation.minValue; - } else { - mOrientationScale = 0; - } - } - } - - mOrientedRanges.haveOrientation = true; - - mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION; - mOrientedRanges.orientation.source = mSource; - mOrientedRanges.orientation.min = -M_PI_2; - mOrientedRanges.orientation.max = M_PI_2; - mOrientedRanges.orientation.flat = 0; - mOrientedRanges.orientation.fuzz = 0; - mOrientedRanges.orientation.resolution = 0; - } - - // Distance - mDistanceScale = 0; - if (mCalibration.distanceCalibration != Calibration::DistanceCalibration::NONE) { - if (mCalibration.distanceCalibration == Calibration::DistanceCalibration::SCALED) { - if (mCalibration.haveDistanceScale) { - mDistanceScale = mCalibration.distanceScale; - } else { - mDistanceScale = 1.0f; - } - } - - mOrientedRanges.haveDistance = true; - - mOrientedRanges.distance.axis = AMOTION_EVENT_AXIS_DISTANCE; - mOrientedRanges.distance.source = mSource; - mOrientedRanges.distance.min = mRawPointerAxes.distance.minValue * mDistanceScale; - mOrientedRanges.distance.max = mRawPointerAxes.distance.maxValue * mDistanceScale; - mOrientedRanges.distance.flat = 0; - mOrientedRanges.distance.fuzz = mRawPointerAxes.distance.fuzz * mDistanceScale; - mOrientedRanges.distance.resolution = 0; - } - - // Compute oriented precision, scales and ranges. - // Note that the maximum value reported is an inclusive maximum value so it is one - // unit less than the total width or height of the display. - switch (mInputDeviceOrientation) { - case DISPLAY_ORIENTATION_90: - case DISPLAY_ORIENTATION_270: - mOrientedXPrecision = mYPrecision; - mOrientedYPrecision = mXPrecision; - - mOrientedRanges.x.min = 0; - mOrientedRanges.x.max = mDisplayHeight - 1; - mOrientedRanges.x.flat = 0; - mOrientedRanges.x.fuzz = 0; - mOrientedRanges.x.resolution = mRawPointerAxes.y.resolution * mYScale; - - mOrientedRanges.y.min = 0; - mOrientedRanges.y.max = mDisplayWidth - 1; - mOrientedRanges.y.flat = 0; - mOrientedRanges.y.fuzz = 0; - mOrientedRanges.y.resolution = mRawPointerAxes.x.resolution * mXScale; - break; - - default: - mOrientedXPrecision = mXPrecision; - mOrientedYPrecision = mYPrecision; - - mOrientedRanges.x.min = 0; - mOrientedRanges.x.max = mDisplayWidth - 1; - mOrientedRanges.x.flat = 0; - mOrientedRanges.x.fuzz = 0; - mOrientedRanges.x.resolution = mRawPointerAxes.x.resolution * mXScale; - - mOrientedRanges.y.min = 0; - mOrientedRanges.y.max = mDisplayHeight - 1; - mOrientedRanges.y.flat = 0; - mOrientedRanges.y.fuzz = 0; - mOrientedRanges.y.resolution = mRawPointerAxes.y.resolution * mYScale; - break; - } + initializeOrientedRanges(); // Location updateAffineTransformation(); @@ -1267,26 +1316,8 @@ void TouchInputMapper::resolveCalibration() { void TouchInputMapper::dumpCalibration(std::string& dump) { dump += INDENT3 "Calibration:\n"; - // Size - switch (mCalibration.sizeCalibration) { - case Calibration::SizeCalibration::NONE: - dump += INDENT4 "touch.size.calibration: none\n"; - break; - case Calibration::SizeCalibration::GEOMETRIC: - dump += INDENT4 "touch.size.calibration: geometric\n"; - break; - case Calibration::SizeCalibration::DIAMETER: - dump += INDENT4 "touch.size.calibration: diameter\n"; - break; - case Calibration::SizeCalibration::BOX: - dump += INDENT4 "touch.size.calibration: box\n"; - break; - case Calibration::SizeCalibration::AREA: - dump += INDENT4 "touch.size.calibration: area\n"; - break; - default: - ALOG_ASSERT(false); - } + dump += INDENT4 "touch.size.calibration: "; + dump += ftl::enum_string(mCalibration.sizeCalibration) + "\n"; if (mCalibration.haveSizeScale) { dump += StringPrintf(INDENT4 "touch.size.scale: %0.3f\n", mCalibration.sizeScale); diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h index 9b020a609a..9fd30e40f3 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchInputMapper.h @@ -243,6 +243,7 @@ protected: DIAMETER, BOX, AREA, + ftl_last = AREA }; SizeCalibration sizeCalibration; @@ -732,6 +733,10 @@ private: void resetExternalStylus(); void clearStylusDataPendingFlags(); + int32_t clampResolution(const char* axisName, int32_t resolution) const; + void initializeOrientedRanges(); + void initializeSizeRanges(); + void sync(nsecs_t when, nsecs_t readTime); bool consumeRawTouches(nsecs_t when, nsecs_t readTime, uint32_t policyFlags); diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index ba70929792..0814bc2be8 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -1003,6 +1003,7 @@ public: mInfo.ownerPid = INJECTOR_PID; mInfo.ownerUid = INJECTOR_UID; mInfo.displayId = displayId; + mInfo.trustedOverlay = false; } sp<FakeWindowHandle> clone( @@ -1054,7 +1055,9 @@ public: void setFlags(Flags<WindowInfo::Flag> flags) { mInfo.flags = flags; } - void setInputFeatures(WindowInfo::Feature features) { mInfo.inputFeatures = features; } + void setInputFeatures(Flags<WindowInfo::Feature> features) { mInfo.inputFeatures = features; } + + void setTrustedOverlay(bool trustedOverlay) { mInfo.trustedOverlay = trustedOverlay; } void setWindowTransform(float dsdx, float dtdx, float dtdy, float dsdy) { mInfo.transform.set(dsdx, dtdx, dtdy, dsdy); @@ -2183,6 +2186,33 @@ TEST_F(InputDispatcherDisplayProjectionTest, InjectionInLogicalDisplaySpace) { secondWindow->assertNoEvents(); } +// Ensure that when a MotionEvent that has a custom transform is injected, the post-transformed +// event should be treated as being in the logical display space. +TEST_F(InputDispatcherDisplayProjectionTest, InjectionWithTransformInLogicalDisplaySpace) { + auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); + + const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0}; + ui::Transform injectedEventTransform; + injectedEventTransform.set(matrix); + const vec2 expectedPoint{75, 55}; // The injected point in the logical display space. + const vec2 untransformedPoint = injectedEventTransform.inverse().transform(expectedPoint); + + MotionEvent event = MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .displayId(ADISPLAY_ID_DEFAULT) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(untransformedPoint.x) + .y(untransformedPoint.y)) + .build(); + event.transform(matrix); + + injectMotionEvent(mDispatcher, event, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT); + + firstWindow->consumeMotionDown(); + secondWindow->assertNoEvents(); +} + TEST_F(InputDispatcherDisplayProjectionTest, WindowGetsEventsInCorrectCoordinateSpace) { auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); @@ -6297,6 +6327,7 @@ public: sp<FakeWindowHandle> spy = new FakeWindowHandle(application, mDispatcher, name.c_str(), ADISPLAY_ID_DEFAULT); spy->setInputFeatures(WindowInfo::Feature::SPY); + spy->setTrustedOverlay(true); spy->addFlags(flags); return spy; } @@ -6315,6 +6346,16 @@ private: }; /** + * Adding a spy window that is not a trusted overlay causes Dispatcher to abort. + */ +TEST_F(InputDispatcherSpyWindowTest, UntrustedSpy_AbortsDispatcher) { + auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); + spy->setTrustedOverlay(false); + ASSERT_DEATH(mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy}}}), + ".* not a trusted overlay"); +} + +/** * Input injection into a display with a spy window but no foreground windows should succeed. */ TEST_F(InputDispatcherSpyWindowTest, NoForegroundWindow) { @@ -6474,28 +6515,6 @@ TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) { } /** - * When configured to block untrusted touches, events will not be dispatched to windows below a spy - * window if it is not a trusted overly. - */ -TEST_F(InputDispatcherSpyWindowTest, BlockUntrustedTouches) { - mDispatcher->setBlockUntrustedTouchesMode(android::os::BlockUntrustedTouchesMode::BLOCK); - - auto window = createForeground(); - auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); - window->setOwnerInfo(111, 111); - spy->setOwnerInfo(222, 222); - spy->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); - - // Inject an event outside the spy window's frame and touchable region. - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) - << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; - spy->consumeMotionDown(); - window->assertNoEvents(); -} - -/** * A spy window can pilfer pointers. When this happens, touch gestures that are currently sent to * any other windows - including other spy windows - will also be cancelled. */ @@ -6600,4 +6619,97 @@ TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) { spyRight->consumeMotionDown(); } +class InputDispatcherStylusInterceptorTest : public InputDispatcherTest { +public: + std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupStylusOverlayScenario() { + std::shared_ptr<FakeApplicationHandle> overlayApplication = + std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> overlay = + new FakeWindowHandle(overlayApplication, mDispatcher, "Stylus interceptor window", + ADISPLAY_ID_DEFAULT); + overlay->setFocusable(false); + overlay->setOwnerInfo(111, 111); + overlay->setFlags(WindowInfo::Flag::NOT_TOUCHABLE | WindowInfo::Flag::SPLIT_TOUCH); + overlay->setInputFeatures(WindowInfo::Feature::INTERCEPTS_STYLUS); + overlay->setTrustedOverlay(true); + + std::shared_ptr<FakeApplicationHandle> application = + std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> window = + new FakeWindowHandle(application, mDispatcher, "Application window", + ADISPLAY_ID_DEFAULT); + window->setFocusable(true); + window->setOwnerInfo(222, 222); + window->setFlags(WindowInfo::Flag::SPLIT_TOUCH); + + mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}}); + setFocusedWindow(window); + window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/); + return {std::move(overlay), std::move(window)}; + } + + void sendFingerEvent(int32_t action) { + NotifyMotionArgs motionArgs = + generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS, + ADISPLAY_ID_DEFAULT, {PointF{20, 20}}); + mDispatcher->notifyMotion(&motionArgs); + } + + void sendStylusEvent(int32_t action) { + NotifyMotionArgs motionArgs = + generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS, + ADISPLAY_ID_DEFAULT, {PointF{30, 40}}); + motionArgs.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + mDispatcher->notifyMotion(&motionArgs); + } +}; + +TEST_F(InputDispatcherStylusInterceptorTest, UntrustedOverlay_AbortsDispatcher) { + auto [overlay, window] = setupStylusOverlayScenario(); + overlay->setTrustedOverlay(false); + // Configuring an untrusted overlay as a stylus interceptor should cause Dispatcher to abort. + ASSERT_DEATH(mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}}), + ".* not a trusted overlay"); +} + +TEST_F(InputDispatcherStylusInterceptorTest, ConsmesOnlyStylusEvents) { + auto [overlay, window] = setupStylusOverlayScenario(); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}}); + + sendStylusEvent(AMOTION_EVENT_ACTION_DOWN); + overlay->consumeMotionDown(); + sendStylusEvent(AMOTION_EVENT_ACTION_UP); + overlay->consumeMotionUp(); + + sendFingerEvent(AMOTION_EVENT_ACTION_DOWN); + window->consumeMotionDown(); + sendFingerEvent(AMOTION_EVENT_ACTION_UP); + window->consumeMotionUp(); + + overlay->assertNoEvents(); + window->assertNoEvents(); +} + +TEST_F(InputDispatcherStylusInterceptorTest, SpyWindowStylusInterceptor) { + auto [overlay, window] = setupStylusOverlayScenario(); + overlay->setInputFeatures(overlay->getInfo()->inputFeatures | WindowInfo::Feature::SPY); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}}); + + sendStylusEvent(AMOTION_EVENT_ACTION_DOWN); + overlay->consumeMotionDown(); + window->consumeMotionDown(); + sendStylusEvent(AMOTION_EVENT_ACTION_UP); + overlay->consumeMotionUp(); + window->consumeMotionUp(); + + sendFingerEvent(AMOTION_EVENT_ACTION_DOWN); + window->consumeMotionDown(); + sendFingerEvent(AMOTION_EVENT_ACTION_UP); + window->consumeMotionUp(); + + overlay->assertNoEvents(); + window->assertNoEvents(); +} + } // namespace android::inputdispatcher diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 336afc67fc..2c5b32140d 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -78,6 +78,15 @@ static constexpr int32_t LIGHT_BRIGHTNESS = 0x55000000; static constexpr int32_t LIGHT_COLOR = 0x7F448866; static constexpr int32_t LIGHT_PLAYER_ID = 2; +static constexpr int32_t ACTION_POINTER_0_DOWN = + AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); +static constexpr int32_t ACTION_POINTER_0_UP = + AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); +static constexpr int32_t ACTION_POINTER_1_DOWN = + AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); +static constexpr int32_t ACTION_POINTER_1_UP = + AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); + // Error tolerance for floating point assertions. static const float EPSILON = 0.001f; @@ -106,6 +115,24 @@ static int32_t getInverseRotation(int32_t orientation) { } } +static void assertAxisResolution(MultiTouchInputMapper& mapper, int axis, float resolution) { + InputDeviceInfo info; + mapper.populateDeviceInfo(&info); + + const InputDeviceInfo::MotionRange* motionRange = + info.getMotionRange(axis, AINPUT_SOURCE_TOUCHSCREEN); + ASSERT_NEAR(motionRange->resolution, resolution, EPSILON); +} + +static void assertAxisNotPresent(MultiTouchInputMapper& mapper, int axis) { + InputDeviceInfo info; + mapper.populateDeviceInfo(&info); + + const InputDeviceInfo::MotionRange* motionRange = + info.getMotionRange(axis, AINPUT_SOURCE_TOUCHSCREEN); + ASSERT_EQ(nullptr, motionRange); +} + // --- FakePointerController --- class FakePointerController : public PointerControllerInterface { @@ -2303,6 +2330,17 @@ protected: mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_DISPLAY_INFO); } + void assertReceivedMotion(int32_t action, const std::vector<Point>& points) { + NotifyMotionArgs args; + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); + EXPECT_EQ(action, args.action); + ASSERT_EQ(points.size(), args.pointerCount); + for (size_t i = 0; i < args.pointerCount; i++) { + EXPECT_EQ(points[i].x, args.pointerCoords[i].getX()); + EXPECT_EQ(points[i].y, args.pointerCoords[i].getY()); + } + } + std::unique_ptr<UinputTouchScreen> mDevice; }; @@ -2313,16 +2351,19 @@ TEST_F(TouchIntegrationTest, InputEvent_ProcessSingleTouch) { // ACTION_DOWN mDevice->sendTrackingId(FIRST_TRACKING_ID); mDevice->sendDown(centerPoint); + mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); // ACTION_MOVE mDevice->sendMove(centerPoint + Point(1, 1)); + mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); // ACTION_UP mDevice->sendUp(); + mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); } @@ -2335,6 +2376,7 @@ TEST_F(TouchIntegrationTest, InputEvent_ProcessMultiTouch) { mDevice->sendSlot(FIRST_SLOT); mDevice->sendTrackingId(FIRST_TRACKING_ID); mDevice->sendDown(centerPoint); + mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); @@ -2342,29 +2384,129 @@ TEST_F(TouchIntegrationTest, InputEvent_ProcessMultiTouch) { const Point secondPoint = centerPoint + Point(100, 100); mDevice->sendSlot(SECOND_SLOT); mDevice->sendTrackingId(SECOND_TRACKING_ID); - mDevice->sendDown(secondPoint + Point(1, 1)); + mDevice->sendDown(secondPoint); + mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - args.action); + ASSERT_EQ(ACTION_POINTER_1_DOWN, args.action); // ACTION_MOVE (Second slot) - mDevice->sendMove(secondPoint); + mDevice->sendMove(secondPoint + Point(1, 1)); + mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); // ACTION_POINTER_UP (Second slot) mDevice->sendPointerUp(); + mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - args.action); + ASSERT_EQ(ACTION_POINTER_1_UP, args.action); // ACTION_UP mDevice->sendSlot(FIRST_SLOT); mDevice->sendUp(); + mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); } +/** + * What happens when a pointer goes up while another pointer moves in the same frame? Are POINTER_UP + * events guaranteed to contain the same data as a preceding MOVE, or can they contain different + * data? + * In this test, we try to send a change in coordinates in Pointer 0 in the same frame as the + * liftoff of Pointer 1. We check that POINTER_UP event is generated first, and the MOVE event + * for Pointer 0 only is generated after. + * Suppose we are only interested in learning the movement of Pointer 0. If we only observe MOVE + * events, we will not miss any information. + * Even though the Pointer 1 up event contains updated Pointer 0 coordinates, there is another MOVE + * event generated afterwards that contains the newest movement of pointer 0. + * This is important for palm rejection. If there is a subsequent InputListener stage that detects + * palms, and wants to cancel Pointer 1, then it is safe to simply drop POINTER_1_UP event without + * losing information about non-palm pointers. + */ +TEST_F(TouchIntegrationTest, MultiTouch_PointerMoveAndSecondPointerUp) { + NotifyMotionArgs args; + const Point centerPoint = mDevice->getCenterPoint(); + + // ACTION_DOWN + mDevice->sendSlot(FIRST_SLOT); + mDevice->sendTrackingId(FIRST_TRACKING_ID); + mDevice->sendDown(centerPoint); + mDevice->sendSync(); + assertReceivedMotion(AMOTION_EVENT_ACTION_DOWN, {centerPoint}); + + // ACTION_POINTER_DOWN (Second slot) + const Point secondPoint = centerPoint + Point(100, 100); + mDevice->sendSlot(SECOND_SLOT); + mDevice->sendTrackingId(SECOND_TRACKING_ID); + mDevice->sendDown(secondPoint); + mDevice->sendSync(); + assertReceivedMotion(ACTION_POINTER_1_DOWN, {centerPoint, secondPoint}); + + // ACTION_MOVE (First slot) + mDevice->sendSlot(FIRST_SLOT); + mDevice->sendMove(centerPoint + Point(5, 5)); + // ACTION_POINTER_UP (Second slot) + mDevice->sendSlot(SECOND_SLOT); + mDevice->sendPointerUp(); + // Send a single sync for the above 2 pointer updates + mDevice->sendSync(); + + // First, we should get POINTER_UP for the second pointer + assertReceivedMotion(ACTION_POINTER_1_UP, + {/*first pointer */ centerPoint + Point(5, 5), + /*second pointer*/ secondPoint}); + + // Next, the MOVE event for the first pointer + assertReceivedMotion(AMOTION_EVENT_ACTION_MOVE, {centerPoint + Point(5, 5)}); +} + +/** + * Similar scenario as above. The difference is that when the second pointer goes up, it will first + * move, and then it will go up, all in the same frame. + * In this scenario, the movement of the second pointer just prior to liftoff is ignored, and never + * gets sent to the listener. + */ +TEST_F(TouchIntegrationTest, MultiTouch_PointerMoveAndSecondPointerMoveAndUp) { + NotifyMotionArgs args; + const Point centerPoint = mDevice->getCenterPoint(); + + // ACTION_DOWN + mDevice->sendSlot(FIRST_SLOT); + mDevice->sendTrackingId(FIRST_TRACKING_ID); + mDevice->sendDown(centerPoint); + mDevice->sendSync(); + assertReceivedMotion(AMOTION_EVENT_ACTION_DOWN, {centerPoint}); + + // ACTION_POINTER_DOWN (Second slot) + const Point secondPoint = centerPoint + Point(100, 100); + mDevice->sendSlot(SECOND_SLOT); + mDevice->sendTrackingId(SECOND_TRACKING_ID); + mDevice->sendDown(secondPoint); + mDevice->sendSync(); + assertReceivedMotion(ACTION_POINTER_1_DOWN, {centerPoint, secondPoint}); + + // ACTION_MOVE (First slot) + mDevice->sendSlot(FIRST_SLOT); + mDevice->sendMove(centerPoint + Point(5, 5)); + // ACTION_POINTER_UP (Second slot) + mDevice->sendSlot(SECOND_SLOT); + mDevice->sendMove(secondPoint + Point(6, 6)); + mDevice->sendPointerUp(); + // Send a single sync for the above 2 pointer updates + mDevice->sendSync(); + + // First, we should get POINTER_UP for the second pointer + // The movement of the second pointer during the liftoff frame is ignored. + // The coordinates 'secondPoint + Point(6, 6)' are never sent to the listener. + assertReceivedMotion(ACTION_POINTER_1_UP, + {/*first pointer */ centerPoint + Point(5, 5), + /*second pointer*/ secondPoint}); + + // Next, the MOVE event for the first pointer + assertReceivedMotion(AMOTION_EVENT_ACTION_MOVE, {centerPoint + Point(5, 5)}); +} + TEST_F(TouchIntegrationTest, InputEvent_ProcessPalm) { NotifyMotionArgs args; const Point centerPoint = mDevice->getCenterPoint(); @@ -2373,6 +2515,7 @@ TEST_F(TouchIntegrationTest, InputEvent_ProcessPalm) { mDevice->sendSlot(FIRST_SLOT); mDevice->sendTrackingId(FIRST_TRACKING_ID); mDevice->sendDown(centerPoint); + mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); @@ -2381,12 +2524,13 @@ TEST_F(TouchIntegrationTest, InputEvent_ProcessPalm) { mDevice->sendSlot(SECOND_SLOT); mDevice->sendTrackingId(SECOND_TRACKING_ID); mDevice->sendDown(secondPoint); + mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - args.action); + ASSERT_EQ(ACTION_POINTER_1_DOWN, args.action); // ACTION_MOVE (second slot) mDevice->sendMove(secondPoint + Point(1, 1)); + mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); @@ -2394,19 +2538,21 @@ TEST_F(TouchIntegrationTest, InputEvent_ProcessPalm) { // a palm event. // Expect to receive the ACTION_POINTER_UP with cancel flag. mDevice->sendToolType(MT_TOOL_PALM); + mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - args.action); + ASSERT_EQ(ACTION_POINTER_1_UP, args.action); ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, args.flags); // Send up to second slot, expect first slot send moving. mDevice->sendPointerUp(); + mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); // Send ACTION_UP (first slot) mDevice->sendSlot(FIRST_SLOT); mDevice->sendUp(); + mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); @@ -6488,7 +6634,7 @@ void MultiTouchInputMapperTest::prepareAxes(int axes) { mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MAJOR, RAW_TOOL_MIN, RAW_TOOL_MAX, 0, 0); if (axes & MINOR) { - mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MINOR, RAW_TOOL_MAX, + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MINOR, RAW_TOOL_MIN, RAW_TOOL_MAX, 0, 0); } } @@ -6622,8 +6768,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); + ASSERT_EQ(ACTION_POINTER_1_DOWN, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); @@ -6683,8 +6828,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); + ASSERT_EQ(ACTION_POINTER_0_UP, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); @@ -6759,8 +6903,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); + ASSERT_EQ(ACTION_POINTER_0_DOWN, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); @@ -6789,8 +6932,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); + ASSERT_EQ(ACTION_POINTER_1_UP, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); @@ -6855,6 +6997,57 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); } +TEST_F(MultiTouchInputMapperTest, AxisResolution_IsPopulated) { + addConfigurationProperty("touch.deviceType", "touchScreen"); + prepareDisplay(DISPLAY_ORIENTATION_0); + + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX, /*flat*/ 0, + /*fuzz*/ 0, /*resolution*/ 10); + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, RAW_Y_MIN, RAW_Y_MAX, /*flat*/ 0, + /*fuzz*/ 0, /*resolution*/ 11); + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOUCH_MAJOR, RAW_TOUCH_MIN, RAW_TOUCH_MAX, + /*flat*/ 0, /*fuzz*/ 0, /*resolution*/ 12); + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOUCH_MINOR, RAW_TOUCH_MIN, RAW_TOUCH_MAX, + /*flat*/ 0, /*fuzz*/ 0, /*resolution*/ 13); + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MAJOR, RAW_TOOL_MIN, RAW_TOOL_MAX, + /*flat*/ 0, /*flat*/ 0, /*resolution*/ 14); + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MINOR, RAW_TOOL_MIN, RAW_TOOL_MAX, + /*flat*/ 0, /*flat*/ 0, /*resolution*/ 15); + + MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); + + // X and Y axes + assertAxisResolution(mapper, AMOTION_EVENT_AXIS_X, 10 / X_PRECISION); + assertAxisResolution(mapper, AMOTION_EVENT_AXIS_Y, 11 / Y_PRECISION); + // Touch major and minor + assertAxisResolution(mapper, AMOTION_EVENT_AXIS_TOUCH_MAJOR, 12 * GEOMETRIC_SCALE); + assertAxisResolution(mapper, AMOTION_EVENT_AXIS_TOUCH_MINOR, 13 * GEOMETRIC_SCALE); + // Tool major and minor + assertAxisResolution(mapper, AMOTION_EVENT_AXIS_TOOL_MAJOR, 14 * GEOMETRIC_SCALE); + assertAxisResolution(mapper, AMOTION_EVENT_AXIS_TOOL_MINOR, 15 * GEOMETRIC_SCALE); +} + +TEST_F(MultiTouchInputMapperTest, TouchMajorAndMinorAxes_DoNotAppearIfNotSupported) { + addConfigurationProperty("touch.deviceType", "touchScreen"); + prepareDisplay(DISPLAY_ORIENTATION_0); + + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX, /*flat*/ 0, + /*fuzz*/ 0, /*resolution*/ 10); + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, RAW_Y_MIN, RAW_Y_MAX, /*flat*/ 0, + /*fuzz*/ 0, /*resolution*/ 11); + + // We do not add ABS_MT_TOUCH_MAJOR / MINOR or ABS_MT_WIDTH_MAJOR / MINOR axes + + MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); + + // Touch major and minor + assertAxisNotPresent(mapper, AMOTION_EVENT_AXIS_TOUCH_MAJOR); + assertAxisNotPresent(mapper, AMOTION_EVENT_AXIS_TOUCH_MINOR); + // Tool major and minor + assertAxisNotPresent(mapper, AMOTION_EVENT_AXIS_TOOL_MAJOR); + assertAxisNotPresent(mapper, AMOTION_EVENT_AXIS_TOOL_MINOR); +} + TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingIds) { addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); @@ -6885,8 +7078,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingId toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); + ASSERT_EQ(ACTION_POINTER_1_DOWN, motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); @@ -6927,8 +7119,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingId processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); + ASSERT_EQ(ACTION_POINTER_0_UP, motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); @@ -6973,8 +7164,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingId processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); + ASSERT_EQ(ACTION_POINTER_0_DOWN, motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); @@ -6993,8 +7183,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingId processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); + ASSERT_EQ(ACTION_POINTER_1_UP, motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); @@ -7059,8 +7248,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithSlots) { toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); + ASSERT_EQ(ACTION_POINTER_1_DOWN, motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); @@ -7100,8 +7288,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithSlots) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); + ASSERT_EQ(ACTION_POINTER_0_UP, motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); @@ -7142,8 +7329,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithSlots) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); + ASSERT_EQ(ACTION_POINTER_0_DOWN, motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); @@ -7163,8 +7349,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithSlots) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); + ASSERT_EQ(ACTION_POINTER_1_UP, motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); @@ -7329,8 +7514,7 @@ TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_SummedLinearCalibrati ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - args.action); + ASSERT_EQ(ACTION_POINTER_1_DOWN, args.action); ASSERT_EQ(size_t(2), args.pointerCount); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], x, y, 1.0f, size, touch, touch, tool, tool, 0, 0)); @@ -8460,8 +8644,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_TwoPointers) processPosition(mapper, x2, y2); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); + ASSERT_EQ(ACTION_POINTER_1_DOWN, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); // If the tool type of the first finger changes to MT_TOOL_PALM, @@ -8471,8 +8654,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_TwoPointers) processToolType(mapper, MT_TOOL_PALM); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); + ASSERT_EQ(ACTION_POINTER_0_UP, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags); // The following MOVE events of second finger should be processed. @@ -8537,8 +8719,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_ShouldCancelW processPosition(mapper, x2, y2); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); + ASSERT_EQ(ACTION_POINTER_1_DOWN, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); // If the tool type of the first finger changes to MT_TOOL_PALM, @@ -8548,8 +8729,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_ShouldCancelW processToolType(mapper, MT_TOOL_PALM); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); + ASSERT_EQ(ACTION_POINTER_0_UP, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags); // Second finger keeps moving. @@ -8637,8 +8817,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_KeepFirstPoin processPosition(mapper, x2, y2); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); + ASSERT_EQ(ACTION_POINTER_1_DOWN, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); // If the tool type of the second finger changes to MT_TOOL_PALM, @@ -8647,8 +8826,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_KeepFirstPoin processToolType(mapper, MT_TOOL_PALM); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); + ASSERT_EQ(ACTION_POINTER_1_UP, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags); // The following MOVE event should be processed. @@ -8722,8 +8900,7 @@ TEST_F(MultiTouchInputMapperTest, Process_MultiTouch_WithInvalidTrackingId) { processPressure(mapper, RAW_PRESSURE_MAX); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); + ASSERT_EQ(ACTION_POINTER_1_DOWN, motionArgs.action); ASSERT_EQ(uint32_t(2), motionArgs.pointerCount); // second finger up with some unexpected data. @@ -8732,8 +8909,7 @@ TEST_F(MultiTouchInputMapperTest, Process_MultiTouch_WithInvalidTrackingId) { processPosition(mapper, x2, y2); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); + ASSERT_EQ(ACTION_POINTER_1_UP, motionArgs.action); ASSERT_EQ(uint32_t(2), motionArgs.pointerCount); // first finger up with some unexpected data. @@ -8845,8 +9021,7 @@ TEST_F(MultiTouchInputMapperTest, Process_TouchpadCapture) { // expect coord[0] to contain previous location, coord[1] to contain new touch 1 location ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - args.action); + ASSERT_EQ(ACTION_POINTER_1_DOWN, args.action); ASSERT_EQ(2U, args.pointerCount); ASSERT_EQ(0, args.pointerProperties[0].id); ASSERT_EQ(1, args.pointerProperties[1].id); diff --git a/services/inputflinger/tests/UinputDevice.cpp b/services/inputflinger/tests/UinputDevice.cpp index 7fec2c8b4b..132b877bb9 100644 --- a/services/inputflinger/tests/UinputDevice.cpp +++ b/services/inputflinger/tests/UinputDevice.cpp @@ -170,28 +170,27 @@ void UinputTouchScreen::sendDown(const Point& point) { injectEvent(EV_KEY, BTN_TOUCH, 1); injectEvent(EV_ABS, ABS_MT_POSITION_X, point.x); injectEvent(EV_ABS, ABS_MT_POSITION_Y, point.y); - injectEvent(EV_SYN, SYN_REPORT, 0); } void UinputTouchScreen::sendMove(const Point& point) { injectEvent(EV_ABS, ABS_MT_POSITION_X, point.x); injectEvent(EV_ABS, ABS_MT_POSITION_Y, point.y); - injectEvent(EV_SYN, SYN_REPORT, 0); } void UinputTouchScreen::sendPointerUp() { sendTrackingId(0xffffffff); - injectEvent(EV_SYN, SYN_REPORT, 0); } void UinputTouchScreen::sendUp() { sendTrackingId(0xffffffff); injectEvent(EV_KEY, BTN_TOUCH, 0); - injectEvent(EV_SYN, SYN_REPORT, 0); } void UinputTouchScreen::sendToolType(int32_t toolType) { injectEvent(EV_ABS, ABS_MT_TOOL_TYPE, toolType); +} + +void UinputTouchScreen::sendSync() { injectEvent(EV_SYN, SYN_REPORT, 0); } diff --git a/services/inputflinger/tests/UinputDevice.h b/services/inputflinger/tests/UinputDevice.h index 01a557cc70..a37fc2b790 100644 --- a/services/inputflinger/tests/UinputDevice.h +++ b/services/inputflinger/tests/UinputDevice.h @@ -142,6 +142,7 @@ public: void sendPointerUp(); void sendUp(); void sendToolType(int32_t toolType); + void sendSync(); const Point getCenterPoint(); diff --git a/services/sensorservice/AidlSensorHalWrapper.cpp b/services/sensorservice/AidlSensorHalWrapper.cpp new file mode 100644 index 0000000000..049d06a540 --- /dev/null +++ b/services/sensorservice/AidlSensorHalWrapper.cpp @@ -0,0 +1,673 @@ +/* + * Copyright (C) 2021 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 "AidlSensorHalWrapper.h" +#include "ISensorsWrapper.h" +#include "SensorDeviceUtils.h" +#include "android/hardware/sensors/2.0/types.h" + +#include <aidl/android/hardware/sensors/BnSensorsCallback.h> +#include <aidlcommonsupport/NativeHandle.h> +#include <android-base/logging.h> +#include <android/binder_manager.h> + +using ::aidl::android::hardware::sensors::AdditionalInfo; +using ::aidl::android::hardware::sensors::DynamicSensorInfo; +using ::aidl::android::hardware::sensors::Event; +using ::aidl::android::hardware::sensors::ISensors; +using ::aidl::android::hardware::sensors::SensorInfo; +using ::aidl::android::hardware::sensors::SensorStatus; +using ::aidl::android::hardware::sensors::SensorType; +using ::android::AidlMessageQueue; +using ::android::hardware::EventFlag; +using ::android::hardware::sensors::V2_1::implementation::MAX_RECEIVE_BUFFER_EVENT_COUNT; + +namespace android { + +namespace { + +status_t convertToStatus(ndk::ScopedAStatus status) { + if (status.isOk()) { + return OK; + } else { + switch (status.getExceptionCode()) { + case EX_ILLEGAL_ARGUMENT: { + return BAD_VALUE; + } + case EX_SECURITY: { + return PERMISSION_DENIED; + } + case EX_UNSUPPORTED_OPERATION: { + return INVALID_OPERATION; + } + case EX_SERVICE_SPECIFIC: { + switch (status.getServiceSpecificError()) { + case ISensors::ERROR_BAD_VALUE: { + return BAD_VALUE; + } + case ISensors::ERROR_NO_MEMORY: { + return NO_MEMORY; + } + default: { + return UNKNOWN_ERROR; + } + } + } + default: { + return UNKNOWN_ERROR; + } + } + } +} + +void convertToSensor(const SensorInfo &src, sensor_t *dst) { + dst->name = strdup(src.name.c_str()); + dst->vendor = strdup(src.vendor.c_str()); + dst->version = src.version; + dst->handle = src.sensorHandle; + dst->type = (int)src.type; + dst->maxRange = src.maxRange; + dst->resolution = src.resolution; + dst->power = src.power; + dst->minDelay = src.minDelayUs; + dst->fifoReservedEventCount = src.fifoReservedEventCount; + dst->fifoMaxEventCount = src.fifoMaxEventCount; + dst->stringType = strdup(src.typeAsString.c_str()); + dst->requiredPermission = strdup(src.requiredPermission.c_str()); + dst->maxDelay = src.maxDelayUs; + dst->flags = src.flags; + dst->reserved[0] = dst->reserved[1] = 0; +} + +void convertToSensorEvent(const Event &src, sensors_event_t *dst) { + *dst = {.version = sizeof(sensors_event_t), + .sensor = src.sensorHandle, + .type = (int32_t)src.sensorType, + .reserved0 = 0, + .timestamp = src.timestamp}; + + switch (src.sensorType) { + case SensorType::META_DATA: { + // Legacy HALs expect the handle reference in the meta data field. + // Copy it over from the handle of the event. + dst->meta_data.what = (int32_t)src.payload.get<Event::EventPayload::meta>().what; + dst->meta_data.sensor = src.sensorHandle; + // Set the sensor handle to 0 to maintain compatibility. + dst->sensor = 0; + break; + } + + case SensorType::ACCELEROMETER: + case SensorType::MAGNETIC_FIELD: + case SensorType::ORIENTATION: + case SensorType::GYROSCOPE: + case SensorType::GRAVITY: + case SensorType::LINEAR_ACCELERATION: { + dst->acceleration.x = src.payload.get<Event::EventPayload::vec3>().x; + dst->acceleration.y = src.payload.get<Event::EventPayload::vec3>().y; + dst->acceleration.z = src.payload.get<Event::EventPayload::vec3>().z; + dst->acceleration.status = (int32_t)src.payload.get<Event::EventPayload::vec3>().status; + break; + } + + case SensorType::GAME_ROTATION_VECTOR: { + dst->data[0] = src.payload.get<Event::EventPayload::vec4>().x; + dst->data[1] = src.payload.get<Event::EventPayload::vec4>().y; + dst->data[2] = src.payload.get<Event::EventPayload::vec4>().z; + dst->data[3] = src.payload.get<Event::EventPayload::vec4>().w; + break; + } + + case SensorType::ROTATION_VECTOR: + case SensorType::GEOMAGNETIC_ROTATION_VECTOR: { + dst->data[0] = src.payload.get<Event::EventPayload::data>().values[0]; + dst->data[1] = src.payload.get<Event::EventPayload::data>().values[1]; + dst->data[2] = src.payload.get<Event::EventPayload::data>().values[2]; + dst->data[3] = src.payload.get<Event::EventPayload::data>().values[3]; + dst->data[4] = src.payload.get<Event::EventPayload::data>().values[4]; + break; + } + + case SensorType::MAGNETIC_FIELD_UNCALIBRATED: + case SensorType::GYROSCOPE_UNCALIBRATED: + case SensorType::ACCELEROMETER_UNCALIBRATED: { + dst->uncalibrated_gyro.x_uncalib = src.payload.get<Event::EventPayload::uncal>().x; + dst->uncalibrated_gyro.y_uncalib = src.payload.get<Event::EventPayload::uncal>().y; + dst->uncalibrated_gyro.z_uncalib = src.payload.get<Event::EventPayload::uncal>().z; + dst->uncalibrated_gyro.x_bias = src.payload.get<Event::EventPayload::uncal>().xBias; + dst->uncalibrated_gyro.y_bias = src.payload.get<Event::EventPayload::uncal>().yBias; + dst->uncalibrated_gyro.z_bias = src.payload.get<Event::EventPayload::uncal>().zBias; + break; + } + + case SensorType::HINGE_ANGLE: + case SensorType::DEVICE_ORIENTATION: + case SensorType::LIGHT: + case SensorType::PRESSURE: + case SensorType::PROXIMITY: + case SensorType::RELATIVE_HUMIDITY: + case SensorType::AMBIENT_TEMPERATURE: + case SensorType::SIGNIFICANT_MOTION: + case SensorType::STEP_DETECTOR: + case SensorType::TILT_DETECTOR: + case SensorType::WAKE_GESTURE: + case SensorType::GLANCE_GESTURE: + case SensorType::PICK_UP_GESTURE: + case SensorType::WRIST_TILT_GESTURE: + case SensorType::STATIONARY_DETECT: + case SensorType::MOTION_DETECT: + case SensorType::HEART_BEAT: + case SensorType::LOW_LATENCY_OFFBODY_DETECT: { + dst->data[0] = src.payload.get<Event::EventPayload::scalar>(); + break; + } + + case SensorType::STEP_COUNTER: { + dst->u64.step_counter = src.payload.get<Event::EventPayload::stepCount>(); + break; + } + + case SensorType::HEART_RATE: { + dst->heart_rate.bpm = src.payload.get<Event::EventPayload::heartRate>().bpm; + dst->heart_rate.status = + (int8_t)src.payload.get<Event::EventPayload::heartRate>().status; + break; + } + + case SensorType::POSE_6DOF: { // 15 floats + for (size_t i = 0; i < 15; ++i) { + dst->data[i] = src.payload.get<Event::EventPayload::pose6DOF>().values[i]; + } + break; + } + + case SensorType::DYNAMIC_SENSOR_META: { + dst->dynamic_sensor_meta.connected = + src.payload.get<Event::EventPayload::dynamic>().connected; + dst->dynamic_sensor_meta.handle = + src.payload.get<Event::EventPayload::dynamic>().sensorHandle; + dst->dynamic_sensor_meta.sensor = NULL; // to be filled in later + + memcpy(dst->dynamic_sensor_meta.uuid, + src.payload.get<Event::EventPayload::dynamic>().uuid.values.data(), 16); + + break; + } + + case SensorType::ADDITIONAL_INFO: { + const AdditionalInfo &srcInfo = src.payload.get<Event::EventPayload::additional>(); + + additional_info_event_t *dstInfo = &dst->additional_info; + dstInfo->type = (int32_t)srcInfo.type; + dstInfo->serial = srcInfo.serial; + + switch (srcInfo.payload.getTag()) { + case AdditionalInfo::AdditionalInfoPayload::Tag::dataInt32: { + const auto &values = + srcInfo.payload.get<AdditionalInfo::AdditionalInfoPayload::dataInt32>() + .values; + CHECK_EQ(values.size() * sizeof(int32_t), sizeof(dstInfo->data_int32)); + memcpy(dstInfo->data_int32, values.data(), sizeof(dstInfo->data_int32)); + break; + } + case AdditionalInfo::AdditionalInfoPayload::Tag::dataFloat: { + const auto &values = + srcInfo.payload.get<AdditionalInfo::AdditionalInfoPayload::dataFloat>() + .values; + CHECK_EQ(values.size() * sizeof(float), sizeof(dstInfo->data_float)); + memcpy(dstInfo->data_float, values.data(), sizeof(dstInfo->data_float)); + break; + } + default: { + ALOGE("Invalid sensor additional info tag: %d", srcInfo.payload.getTag()); + } + } + break; + } + + default: { + CHECK_GE((int32_t)src.sensorType, (int32_t)SensorType::DEVICE_PRIVATE_BASE); + + memcpy(dst->data, src.payload.get<Event::EventPayload::data>().values.data(), + 16 * sizeof(float)); + break; + } + } +} + +void convertFromSensorEvent(const sensors_event_t &src, Event *dst) { + *dst = { + .timestamp = src.timestamp, + .sensorHandle = src.sensor, + .sensorType = (SensorType) src.type, + }; + + switch (dst->sensorType) { + case SensorType::META_DATA: { + Event::EventPayload::MetaData meta; + meta.what = (Event::EventPayload::MetaData::MetaDataEventType)src.meta_data.what; + // Legacy HALs contain the handle reference in the meta data field. + // Copy that over to the handle of the event. In legacy HALs this + // field was expected to be 0. + dst->sensorHandle = src.meta_data.sensor; + dst->payload.set<Event::EventPayload::Tag::meta>(meta); + break; + } + + case SensorType::ACCELEROMETER: + case SensorType::MAGNETIC_FIELD: + case SensorType::ORIENTATION: + case SensorType::GYROSCOPE: + case SensorType::GRAVITY: + case SensorType::LINEAR_ACCELERATION: { + Event::EventPayload::Vec3 vec3; + vec3.x = src.acceleration.x; + vec3.y = src.acceleration.y; + vec3.z = src.acceleration.z; + vec3.status = (SensorStatus)src.acceleration.status; + dst->payload.set<Event::EventPayload::Tag::vec3>(vec3); + break; + } + + case SensorType::GAME_ROTATION_VECTOR: { + Event::EventPayload::Vec4 vec4; + vec4.x = src.data[0]; + vec4.y = src.data[1]; + vec4.z = src.data[2]; + vec4.w = src.data[3]; + dst->payload.set<Event::EventPayload::Tag::vec4>(vec4); + break; + } + + case SensorType::ROTATION_VECTOR: + case SensorType::GEOMAGNETIC_ROTATION_VECTOR: { + Event::EventPayload::Data data; + memcpy(data.values.data(), src.data, 5 * sizeof(float)); + dst->payload.set<Event::EventPayload::Tag::data>(data); + break; + } + + case SensorType::MAGNETIC_FIELD_UNCALIBRATED: + case SensorType::GYROSCOPE_UNCALIBRATED: + case SensorType::ACCELEROMETER_UNCALIBRATED: { + Event::EventPayload::Uncal uncal; + uncal.x = src.uncalibrated_gyro.x_uncalib; + uncal.y = src.uncalibrated_gyro.y_uncalib; + uncal.z = src.uncalibrated_gyro.z_uncalib; + uncal.xBias = src.uncalibrated_gyro.x_bias; + uncal.yBias = src.uncalibrated_gyro.y_bias; + uncal.zBias = src.uncalibrated_gyro.z_bias; + dst->payload.set<Event::EventPayload::Tag::uncal>(uncal); + break; + } + + case SensorType::DEVICE_ORIENTATION: + case SensorType::LIGHT: + case SensorType::PRESSURE: + case SensorType::PROXIMITY: + case SensorType::RELATIVE_HUMIDITY: + case SensorType::AMBIENT_TEMPERATURE: + case SensorType::SIGNIFICANT_MOTION: + case SensorType::STEP_DETECTOR: + case SensorType::TILT_DETECTOR: + case SensorType::WAKE_GESTURE: + case SensorType::GLANCE_GESTURE: + case SensorType::PICK_UP_GESTURE: + case SensorType::WRIST_TILT_GESTURE: + case SensorType::STATIONARY_DETECT: + case SensorType::MOTION_DETECT: + case SensorType::HEART_BEAT: + case SensorType::LOW_LATENCY_OFFBODY_DETECT: + case SensorType::HINGE_ANGLE: { + dst->payload.set<Event::EventPayload::Tag::scalar>((float)src.data[0]); + break; + } + + case SensorType::STEP_COUNTER: { + dst->payload.set<Event::EventPayload::Tag::stepCount>(src.u64.step_counter); + break; + } + + case SensorType::HEART_RATE: { + Event::EventPayload::HeartRate heartRate; + heartRate.bpm = src.heart_rate.bpm; + heartRate.status = (SensorStatus)src.heart_rate.status; + dst->payload.set<Event::EventPayload::Tag::heartRate>(heartRate); + break; + } + + case SensorType::POSE_6DOF: { // 15 floats + Event::EventPayload::Pose6Dof pose6DOF; + for (size_t i = 0; i < 15; ++i) { + pose6DOF.values[i] = src.data[i]; + } + dst->payload.set<Event::EventPayload::Tag::pose6DOF>(pose6DOF); + break; + } + + case SensorType::DYNAMIC_SENSOR_META: { + DynamicSensorInfo dynamic; + dynamic.connected = src.dynamic_sensor_meta.connected; + dynamic.sensorHandle = src.dynamic_sensor_meta.handle; + + memcpy(dynamic.uuid.values.data(), src.dynamic_sensor_meta.uuid, 16); + dst->payload.set<Event::EventPayload::Tag::dynamic>(dynamic); + break; + } + + case SensorType::ADDITIONAL_INFO: { + AdditionalInfo info; + const additional_info_event_t &srcInfo = src.additional_info; + info.type = (AdditionalInfo::AdditionalInfoType)srcInfo.type; + info.serial = srcInfo.serial; + + AdditionalInfo::AdditionalInfoPayload::Int32Values data; + CHECK_EQ(data.values.size() * sizeof(int32_t), sizeof(srcInfo.data_int32)); + memcpy(data.values.data(), srcInfo.data_int32, sizeof(srcInfo.data_int32)); + info.payload.set<AdditionalInfo::AdditionalInfoPayload::Tag::dataInt32>(data); + + dst->payload.set<Event::EventPayload::Tag::additional>(info); + break; + } + + default: { + CHECK_GE((int32_t)dst->sensorType, (int32_t)SensorType::DEVICE_PRIVATE_BASE); + + Event::EventPayload::Data data; + memcpy(data.values.data(), src.data, 16 * sizeof(float)); + dst->payload.set<Event::EventPayload::Tag::data>(data); + break; + } + } +} + +void serviceDied(void *cookie) { + ALOGW("Sensors HAL died, attempting to reconnect."); + ((AidlSensorHalWrapper *)cookie)->prepareForReconnect(); +} + +template <typename EnumType> +constexpr typename std::underlying_type<EnumType>::type asBaseType(EnumType value) { + return static_cast<typename std::underlying_type<EnumType>::type>(value); +} + +enum EventQueueFlagBitsInternal : uint32_t { + INTERNAL_WAKE = 1 << 16, +}; + +} // anonymous namespace + +class AidlSensorsCallback : public ::aidl::android::hardware::sensors::BnSensorsCallback { +public: + AidlSensorsCallback(AidlSensorHalWrapper::SensorDeviceCallback *sensorDeviceCallback) + : mSensorDeviceCallback(sensorDeviceCallback) {} + + ::ndk::ScopedAStatus onDynamicSensorsConnected( + const std::vector<SensorInfo> &sensorInfos) override { + std::vector<sensor_t> sensors; + for (const SensorInfo &sensorInfo : sensorInfos) { + sensor_t sensor; + convertToSensor(sensorInfo, &sensor); + sensors.push_back(sensor); + } + + mSensorDeviceCallback->onDynamicSensorsConnected(sensors); + return ::ndk::ScopedAStatus::ok(); + } + + ::ndk::ScopedAStatus onDynamicSensorsDisconnected( + const std::vector<int32_t> &sensorHandles) override { + mSensorDeviceCallback->onDynamicSensorsDisconnected(sensorHandles); + return ::ndk::ScopedAStatus::ok(); + } + +private: + ISensorHalWrapper::SensorDeviceCallback *mSensorDeviceCallback; +}; + +AidlSensorHalWrapper::AidlSensorHalWrapper() + : mEventQueueFlag(nullptr), + mWakeLockQueueFlag(nullptr), + mDeathRecipient(AIBinder_DeathRecipient_new(serviceDied)) {} + +bool AidlSensorHalWrapper::supportsPolling() { + return false; +} + +bool AidlSensorHalWrapper::supportsMessageQueues() { + return true; +} + +bool AidlSensorHalWrapper::connect(SensorDeviceCallback *callback) { + mSensorDeviceCallback = callback; + mSensors = nullptr; + + auto aidlServiceName = std::string() + ISensors::descriptor + "/default"; + if (AServiceManager_isDeclared(aidlServiceName.c_str())) { + if (mSensors != nullptr) { + AIBinder_unlinkToDeath(mSensors->asBinder().get(), mDeathRecipient.get(), this); + } + + ndk::SpAIBinder binder(AServiceManager_waitForService(aidlServiceName.c_str())); + if (binder.get() != nullptr) { + mSensors = ISensors::fromBinder(binder); + mEventQueue = std::make_unique<AidlMessageQueue< + Event, SynchronizedReadWrite>>(MAX_RECEIVE_BUFFER_EVENT_COUNT, + /*configureEventFlagWord=*/true); + + mWakeLockQueue = std::make_unique<AidlMessageQueue< + int32_t, SynchronizedReadWrite>>(MAX_RECEIVE_BUFFER_EVENT_COUNT, + /*configureEventFlagWord=*/true); + if (mEventQueueFlag != nullptr) { + EventFlag::deleteEventFlag(&mEventQueueFlag); + } + EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag); + if (mWakeLockQueueFlag != nullptr) { + EventFlag::deleteEventFlag(&mWakeLockQueueFlag); + } + EventFlag::createEventFlag(mWakeLockQueue->getEventFlagWord(), &mWakeLockQueueFlag); + + CHECK(mEventQueue != nullptr && mEventQueueFlag != nullptr && + mWakeLockQueue != nullptr && mWakeLockQueueFlag != nullptr); + + mCallback = ndk::SharedRefBase::make<AidlSensorsCallback>(mSensorDeviceCallback); + mSensors->initialize(mEventQueue->dupeDesc(), mWakeLockQueue->dupeDesc(), mCallback); + + AIBinder_linkToDeath(mSensors->asBinder().get(), mDeathRecipient.get(), this); + } else { + ALOGE("Could not connect to declared sensors AIDL HAL"); + } + } + + return mSensors != nullptr; +} + +void AidlSensorHalWrapper::prepareForReconnect() { + mReconnecting = true; + if (mEventQueueFlag != nullptr) { + mEventQueueFlag->wake(asBaseType(INTERNAL_WAKE)); + } +} + +ssize_t AidlSensorHalWrapper::poll(sensors_event_t * /* buffer */, size_t /* count */) { + return 0; +} + +ssize_t AidlSensorHalWrapper::pollFmq(sensors_event_t *buffer, size_t maxNumEventsToRead) { + ssize_t eventsRead = 0; + size_t availableEvents = mEventQueue->availableToRead(); + + if (availableEvents == 0) { + uint32_t eventFlagState = 0; + + // Wait for events to become available. This is necessary so that the Event FMQ's read() is + // able to be called with the correct number of events to read. If the specified number of + // events is not available, then read() would return no events, possibly introducing + // additional latency in delivering events to applications. + if (mEventQueueFlag != nullptr) { + mEventQueueFlag->wait(asBaseType(ISensors::EVENT_QUEUE_FLAG_BITS_READ_AND_PROCESS) | + asBaseType(INTERNAL_WAKE), + &eventFlagState); + } + availableEvents = mEventQueue->availableToRead(); + + if ((eventFlagState & asBaseType(INTERNAL_WAKE)) && mReconnecting) { + ALOGD("Event FMQ internal wake, returning from poll with no events"); + return DEAD_OBJECT; + } + } + + size_t eventsToRead = std::min({availableEvents, maxNumEventsToRead, mEventBuffer.size()}); + if (eventsToRead > 0) { + if (mEventQueue->read(mEventBuffer.data(), eventsToRead)) { + // Notify the Sensors HAL that sensor events have been read. This is required to support + // the use of writeBlocking by the Sensors HAL. + if (mEventQueueFlag != nullptr) { + mEventQueueFlag->wake(asBaseType(ISensors::EVENT_QUEUE_FLAG_BITS_EVENTS_READ)); + } + + for (size_t i = 0; i < eventsToRead; i++) { + convertToSensorEvent(mEventBuffer[i], &buffer[i]); + } + eventsRead = eventsToRead; + } else { + ALOGW("Failed to read %zu events, currently %zu events available", eventsToRead, + availableEvents); + } + } + + return eventsRead; +} + +std::vector<sensor_t> AidlSensorHalWrapper::getSensorsList() { + std::vector<sensor_t> sensorsFound; + + if (mSensors != nullptr) { + std::vector<SensorInfo> list; + mSensors->getSensorsList(&list); + for (size_t i = 0; i < list.size(); i++) { + sensor_t sensor; + convertToSensor(list[i], &sensor); + sensorsFound.push_back(sensor); + } + } + + return sensorsFound; +} + +status_t AidlSensorHalWrapper::setOperationMode(SensorService::Mode mode) { + if (mSensors == nullptr) return NO_INIT; + return convertToStatus(mSensors->setOperationMode(static_cast<ISensors::OperationMode>(mode))); +} + +status_t AidlSensorHalWrapper::activate(int32_t sensorHandle, bool enabled) { + if (mSensors == nullptr) return NO_INIT; + return convertToStatus(mSensors->activate(sensorHandle, enabled)); +} + +status_t AidlSensorHalWrapper::batch(int32_t sensorHandle, int64_t samplingPeriodNs, + int64_t maxReportLatencyNs) { + if (mSensors == nullptr) return NO_INIT; + return convertToStatus(mSensors->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs)); +} + +status_t AidlSensorHalWrapper::flush(int32_t sensorHandle) { + if (mSensors == nullptr) return NO_INIT; + return convertToStatus(mSensors->flush(sensorHandle)); +} + +status_t AidlSensorHalWrapper::injectSensorData(const sensors_event_t *event) { + if (mSensors == nullptr) return NO_INIT; + + Event ev; + convertFromSensorEvent(*event, &ev); + return convertToStatus(mSensors->injectSensorData(ev)); +} + +status_t AidlSensorHalWrapper::registerDirectChannel(const sensors_direct_mem_t *memory, + int32_t *channelHandle) { + if (mSensors == nullptr) return NO_INIT; + + ISensors::SharedMemInfo::SharedMemType type; + switch (memory->type) { + case SENSOR_DIRECT_MEM_TYPE_ASHMEM: + type = ISensors::SharedMemInfo::SharedMemType::ASHMEM; + break; + case SENSOR_DIRECT_MEM_TYPE_GRALLOC: + type = ISensors::SharedMemInfo::SharedMemType::GRALLOC; + break; + default: + return BAD_VALUE; + } + + if (memory->format != SENSOR_DIRECT_FMT_SENSORS_EVENT) { + return BAD_VALUE; + } + ISensors::SharedMemInfo::SharedMemFormat format = + ISensors::SharedMemInfo::SharedMemFormat::SENSORS_EVENT; + + ISensors::SharedMemInfo mem = { + .type = type, + .format = format, + .size = static_cast<int32_t>(memory->size), + .memoryHandle = makeToAidl(memory->handle), + }; + + return convertToStatus(mSensors->registerDirectChannel(mem, channelHandle)); +} + +status_t AidlSensorHalWrapper::unregisterDirectChannel(int32_t channelHandle) { + if (mSensors == nullptr) return NO_INIT; + return convertToStatus(mSensors->unregisterDirectChannel(channelHandle)); +} + +status_t AidlSensorHalWrapper::configureDirectChannel(int32_t sensorHandle, int32_t channelHandle, + const struct sensors_direct_cfg_t *config) { + if (mSensors == nullptr) return NO_INIT; + + ISensors::RateLevel rate; + switch (config->rate_level) { + case SENSOR_DIRECT_RATE_STOP: + rate = ISensors::RateLevel::STOP; + break; + case SENSOR_DIRECT_RATE_NORMAL: + rate = ISensors::RateLevel::NORMAL; + break; + case SENSOR_DIRECT_RATE_FAST: + rate = ISensors::RateLevel::FAST; + break; + case SENSOR_DIRECT_RATE_VERY_FAST: + rate = ISensors::RateLevel::VERY_FAST; + break; + default: + return BAD_VALUE; + } + + int32_t token; + mSensors->configDirectReport(sensorHandle, channelHandle, rate, &token); + return token; +} + +void AidlSensorHalWrapper::writeWakeLockHandled(uint32_t count) { + int signedCount = (int)count; + if (mWakeLockQueue->write(&signedCount)) { + mWakeLockQueueFlag->wake(asBaseType(ISensors::WAKE_LOCK_QUEUE_FLAG_BITS_DATA_WRITTEN)); + } else { + ALOGW("Failed to write wake lock handled"); + } +} + +} // namespace android diff --git a/services/sensorservice/AidlSensorHalWrapper.h b/services/sensorservice/AidlSensorHalWrapper.h new file mode 100644 index 0000000000..9f61993923 --- /dev/null +++ b/services/sensorservice/AidlSensorHalWrapper.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_AIDL_SENSOR_HAL_WRAPPER_H +#define ANDROID_AIDL_SENSOR_HAL_WRAPPER_H + +#include "ISensorHalWrapper.h" + +#include <aidl/android/hardware/sensors/ISensors.h> +#include <fmq/AidlMessageQueue.h> +#include <sensor/SensorEventQueue.h> + +namespace android { + +class AidlSensorHalWrapper : public ISensorHalWrapper { +public: + AidlSensorHalWrapper(); + + ~AidlSensorHalWrapper() override { + if (mEventQueueFlag != nullptr) { + ::android::hardware::EventFlag::deleteEventFlag(&mEventQueueFlag); + mEventQueueFlag = nullptr; + } + if (mWakeLockQueueFlag != nullptr) { + ::android::hardware::EventFlag::deleteEventFlag(&mWakeLockQueueFlag); + mWakeLockQueueFlag = nullptr; + } + } + + virtual bool connect(SensorDeviceCallback *callback) override; + + virtual void prepareForReconnect() override; + + virtual bool supportsPolling() override; + + virtual bool supportsMessageQueues() override; + + virtual ssize_t poll(sensors_event_t *buffer, size_t count) override; + + virtual ssize_t pollFmq(sensors_event_t *buffer, size_t count) override; + + virtual std::vector<sensor_t> getSensorsList() override; + + virtual status_t setOperationMode(SensorService::Mode mode) override; + + virtual status_t activate(int32_t sensorHandle, bool enabled) override; + + virtual status_t batch(int32_t sensorHandle, int64_t samplingPeriodNs, + int64_t maxReportLatencyNs) override; + + virtual status_t flush(int32_t sensorHandle) override; + + virtual status_t injectSensorData(const sensors_event_t *event) override; + + virtual status_t registerDirectChannel(const sensors_direct_mem_t *memory, + int32_t *channelHandle) override; + + virtual status_t unregisterDirectChannel(int32_t channelHandle) override; + + virtual status_t configureDirectChannel(int32_t sensorHandle, int32_t channelHandle, + const struct sensors_direct_cfg_t *config) override; + + virtual void writeWakeLockHandled(uint32_t count) override; + +private: + std::shared_ptr<aidl::android::hardware::sensors::ISensors> mSensors; + std::shared_ptr<::aidl::android::hardware::sensors::ISensorsCallback> mCallback; + std::unique_ptr<::android::AidlMessageQueue<::aidl::android::hardware::sensors::Event, + SynchronizedReadWrite>> + mEventQueue; + std::unique_ptr<::android::AidlMessageQueue<int, SynchronizedReadWrite>> mWakeLockQueue; + ::android::hardware::EventFlag *mEventQueueFlag; + ::android::hardware::EventFlag *mWakeLockQueueFlag; + SensorDeviceCallback *mSensorDeviceCallback; + std::array<::aidl::android::hardware::sensors::Event, + ::android::SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT> + mEventBuffer; + + ndk::ScopedAIBinder_DeathRecipient mDeathRecipient; +}; + +} // namespace android + +#endif // ANDROID_AIDL_SENSOR_HAL_WRAPPER_H diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp index f8d9dc2a9d..d5b629d564 100644 --- a/services/sensorservice/Android.bp +++ b/services/sensorservice/Android.bp @@ -11,6 +11,7 @@ cc_library_shared { name: "libsensorservice", srcs: [ + "AidlSensorHalWrapper.cpp", "BatteryService.cpp", "CorrectedGyroSensor.cpp", "Fusion.cpp", @@ -61,14 +62,19 @@ cc_library_shared { "libbase", "libhidlbase", "libfmq", + "libbinder_ndk", "packagemanager_aidl-cpp", "android.hardware.sensors@1.0", "android.hardware.sensors@2.0", "android.hardware.sensors@2.1", + "android.hardware.common-V2-ndk", + "android.hardware.common.fmq-V1-ndk", ], static_libs: [ + "libaidlcommonsupport", "android.hardware.sensors@1.0-convert", + "android.hardware.sensors-V1-ndk", ], generated_headers: ["framework-cppstream-protos"], diff --git a/services/sensorservice/HidlSensorHalWrapper.cpp b/services/sensorservice/HidlSensorHalWrapper.cpp index dbb3da19a6..4c64e59615 100644 --- a/services/sensorservice/HidlSensorHalWrapper.cpp +++ b/services/sensorservice/HidlSensorHalWrapper.cpp @@ -76,11 +76,11 @@ void SensorsHalDeathReceiver::serviceDied( mHidlSensorHalWrapper->prepareForReconnect(); } -struct SensorsCallback : public ISensorsCallback { +struct HidlSensorsCallback : public ISensorsCallback { using Result = ::android::hardware::sensors::V1_0::Result; using SensorInfo = ::android::hardware::sensors::V2_1::SensorInfo; - SensorsCallback(ISensorHalWrapper::SensorDeviceCallback* sensorDeviceCallback) { + HidlSensorsCallback(ISensorHalWrapper::SensorDeviceCallback* sensorDeviceCallback) { mSensorDeviceCallback = sensorDeviceCallback; } @@ -143,18 +143,19 @@ ssize_t HidlSensorHalWrapper::poll(sensors_event_t* buffer, size_t count) { bool hidlTransportError = false; do { - auto ret = mSensors->poll( - count, [&](auto result, const auto& events, const auto& dynamicSensorsAdded) { - if (result == Result::OK) { - convertToSensorEventsAndQuantize(convertToNewEvents(events), - convertToNewSensorInfos( - dynamicSensorsAdded), - buffer); - err = (ssize_t)events.size(); - } else { - err = statusFromResult(result); - } - }); + auto ret = mSensors->poll(count, + [&](auto result, const auto& events, + const auto& dynamicSensorsAdded) { + if (result == Result::OK) { + convertToSensorEvents(convertToNewEvents(events), + convertToNewSensorInfos( + dynamicSensorsAdded), + buffer); + err = (ssize_t)events.size(); + } else { + err = statusFromResult(result); + } + }); if (ret.isOk()) { hidlTransportError = false; @@ -216,9 +217,6 @@ ssize_t HidlSensorHalWrapper::pollFmq(sensors_event_t* buffer, size_t maxNumEven for (size_t i = 0; i < eventsToRead; i++) { convertToSensorEvent(mEventBuffer[i], &buffer[i]); - android::SensorDeviceUtils::quantizeSensorEventValues(&buffer[i], - getResolutionForSensor( - buffer[i].sensor)); } eventsRead = eventsToRead; } else { @@ -482,7 +480,7 @@ ISensorHalWrapper::HalConnectionStatus HidlSensorHalWrapper::initializeHidlServi CHECK(mSensors != nullptr && mWakeLockQueue != nullptr && mEventQueueFlag != nullptr && mWakeLockQueueFlag != nullptr); - mCallback = new SensorsCallback(mSensorDeviceCallback); + mCallback = sp<HidlSensorsCallback>::make(mSensorDeviceCallback); status_t status = checkReturnAndGetStatus(mSensors->initialize(*mWakeLockQueue->getDesc(), mCallback)); @@ -500,63 +498,18 @@ ISensorHalWrapper::HalConnectionStatus HidlSensorHalWrapper::initializeHidlServi void HidlSensorHalWrapper::convertToSensorEvent(const Event& src, sensors_event_t* dst) { android::hardware::sensors::V2_1::implementation::convertToSensorEvent(src, dst); - - if (src.sensorType == android::hardware::sensors::V2_1::SensorType::DYNAMIC_SENSOR_META) { - const hardware::sensors::V1_0::DynamicSensorInfo& dyn = src.u.dynamic; - - dst->dynamic_sensor_meta.connected = dyn.connected; - dst->dynamic_sensor_meta.handle = dyn.sensorHandle; - if (dyn.connected) { - std::unique_lock<std::mutex> lock(mDynamicSensorsMutex); - // Give MAX_DYN_SENSOR_WAIT_SEC for onDynamicSensorsConnected to be invoked since it - // can be received out of order from this event due to a bug in the HIDL spec that - // marks it as oneway. - auto it = mConnectedDynamicSensors.find(dyn.sensorHandle); - if (it == mConnectedDynamicSensors.end()) { - mDynamicSensorsCv.wait_for(lock, MAX_DYN_SENSOR_WAIT, [&, dyn] { - return mConnectedDynamicSensors.find(dyn.sensorHandle) != - mConnectedDynamicSensors.end(); - }); - it = mConnectedDynamicSensors.find(dyn.sensorHandle); - CHECK(it != mConnectedDynamicSensors.end()); - } - - dst->dynamic_sensor_meta.sensor = &it->second; - - memcpy(dst->dynamic_sensor_meta.uuid, dyn.uuid.data(), - sizeof(dst->dynamic_sensor_meta.uuid)); - } - } } -void HidlSensorHalWrapper::convertToSensorEventsAndQuantize( - const hidl_vec<Event>& src, const hidl_vec<SensorInfo>& dynamicSensorsAdded, - sensors_event_t* dst) { +void HidlSensorHalWrapper::convertToSensorEvents(const hidl_vec<Event>& src, + const hidl_vec<SensorInfo>& dynamicSensorsAdded, + sensors_event_t* dst) { if (dynamicSensorsAdded.size() > 0 && mCallback != nullptr) { mCallback->onDynamicSensorsConnected_2_1(dynamicSensorsAdded); } for (size_t i = 0; i < src.size(); ++i) { - android::hardware::sensors::V2_1::implementation::convertToSensorEvent(src[i], &dst[i]); - android::SensorDeviceUtils::quantizeSensorEventValues(&dst[i], - getResolutionForSensor( - dst[i].sensor)); + convertToSensorEvent(src[i], &dst[i]); } } -float HidlSensorHalWrapper::getResolutionForSensor(int sensorHandle) { - for (size_t i = 0; i < mSensorList.size(); i++) { - if (sensorHandle == mSensorList[i].handle) { - return mSensorList[i].resolution; - } - } - - auto it = mConnectedDynamicSensors.find(sensorHandle); - if (it != mConnectedDynamicSensors.end()) { - return it->second.resolution; - } - - return 0; -} - } // namespace android diff --git a/services/sensorservice/HidlSensorHalWrapper.h b/services/sensorservice/HidlSensorHalWrapper.h index 030247fc12..71c3512742 100644 --- a/services/sensorservice/HidlSensorHalWrapper.h +++ b/services/sensorservice/HidlSensorHalWrapper.h @@ -124,12 +124,6 @@ public: private: sp<::android::hardware::sensors::V2_1::implementation::ISensorsWrapperBase> mSensors; sp<::android::hardware::sensors::V2_1::ISensorsCallback> mCallback; - std::vector<sensor_t> mSensorList; - std::unordered_map<int32_t, sensor_t> mConnectedDynamicSensors; - - std::mutex mDynamicSensorsMutex; - std::condition_variable mDynamicSensorsCv; - static constexpr std::chrono::seconds MAX_DYN_SENSOR_WAIT{5}; // Keep track of any hidl transport failures SensorServiceUtil::RingBuffer<HidlTransportErrorLog> mHidlTransportErrors; @@ -153,9 +147,9 @@ private: void convertToSensorEvent(const Event& src, sensors_event_t* dst); - void convertToSensorEventsAndQuantize(const hardware::hidl_vec<Event>& src, - const hardware::hidl_vec<SensorInfo>& dynamicSensorsAdded, - sensors_event_t* dst); + void convertToSensorEvents(const hardware::hidl_vec<Event>& src, + const hardware::hidl_vec<SensorInfo>& dynamicSensorsAdded, + sensors_event_t* dst); bool connectHidlService(); @@ -167,8 +161,6 @@ private: typedef hardware::MessageQueue<uint32_t, hardware::kSynchronizedReadWrite> WakeLockQueue; std::unique_ptr<WakeLockQueue> mWakeLockQueue; - float getResolutionForSensor(int sensorHandle); - hardware::EventFlag* mEventQueueFlag; hardware::EventFlag* mWakeLockQueueFlag; diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp index 84a1076b14..a0e30ac355 100644 --- a/services/sensorservice/SensorDevice.cpp +++ b/services/sensorservice/SensorDevice.cpp @@ -20,10 +20,15 @@ #include "android/hardware/sensors/2.1/types.h" #include "convertV2_1.h" +#include "AidlSensorHalWrapper.h" +#include "HidlSensorHalWrapper.h" + #include <android-base/logging.h> #include <android/util/ProtoOutputStream.h> #include <cutils/atomic.h> #include <frameworks/base/core/proto/android/service/sensor_service.proto.h> +#include <hardware/sensors-base.h> +#include <hardware/sensors.h> #include <sensors/convert.h> #include <utils/Errors.h> #include <utils/Singleton.h> @@ -132,11 +137,18 @@ void SensorDevice::initializeSensorList() { SensorDevice::~SensorDevice() {} bool SensorDevice::connectHalService() { + std::unique_ptr<ISensorHalWrapper> aidl_wrapper = std::make_unique<AidlSensorHalWrapper>(); + if (aidl_wrapper->connect(this)) { + mHalWrapper = std::move(aidl_wrapper); + return true; + } + std::unique_ptr<ISensorHalWrapper> hidl_wrapper = std::make_unique<HidlSensorHalWrapper>(); if (hidl_wrapper->connect(this)) { mHalWrapper = std::move(hidl_wrapper); return true; } + // TODO: check aidl connection; return false; } @@ -349,6 +361,35 @@ ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) { ALOGE("Must support polling or FMQ"); eventsRead = -1; } + + if (eventsRead > 0) { + for (ssize_t i = 0; i < eventsRead; i++) { + float resolution = getResolutionForSensor(buffer[i].sensor); + android::SensorDeviceUtils::quantizeSensorEventValues(&buffer[i], resolution); + + if (buffer[i].type == SENSOR_TYPE_DYNAMIC_SENSOR_META) { + struct dynamic_sensor_meta_event& dyn = buffer[i].dynamic_sensor_meta; + if (dyn.connected) { + std::unique_lock<std::mutex> lock(mDynamicSensorsMutex); + // Give MAX_DYN_SENSOR_WAIT_SEC for onDynamicSensorsConnected to be invoked + // since it can be received out of order from this event due to a bug in the + // HIDL spec that marks it as oneway. + auto it = mConnectedDynamicSensors.find(dyn.handle); + if (it == mConnectedDynamicSensors.end()) { + mDynamicSensorsCv.wait_for(lock, MAX_DYN_SENSOR_WAIT, [&, dyn] { + return mConnectedDynamicSensors.find(dyn.handle) != + mConnectedDynamicSensors.end(); + }); + it = mConnectedDynamicSensors.find(dyn.handle); + CHECK(it != mConnectedDynamicSensors.end()); + } + + dyn.sensor = &it->second; + } + } + } + } + return eventsRead; } @@ -572,6 +613,7 @@ int SensorDevice::getHalDeviceVersion() const { } status_t SensorDevice::flush(void* /*ident*/, int handle) { + if (mHalWrapper == nullptr) return NO_INIT; return mHalWrapper->flush(handle); } @@ -711,6 +753,7 @@ void SensorDevice::disableAllSensors() { } status_t SensorDevice::injectSensorData(const sensors_event_t* injected_sensor_event) { + if (mHalWrapper == nullptr) return NO_INIT; return mHalWrapper->injectSensorData(injected_sensor_event); } @@ -720,6 +763,7 @@ status_t SensorDevice::setMode(uint32_t mode) { } int32_t SensorDevice::registerDirectChannel(const sensors_direct_mem_t* memory) { + if (mHalWrapper == nullptr) return NO_INIT; Mutex::Autolock _l(mLock); return mHalWrapper->registerDirectChannel(memory, nullptr); @@ -731,6 +775,7 @@ void SensorDevice::unregisterDirectChannel(int32_t channelHandle) { int32_t SensorDevice::configureDirectChannel(int32_t sensorHandle, int32_t channelHandle, const struct sensors_direct_cfg_t* config) { + if (mHalWrapper == nullptr) return NO_INIT; Mutex::Autolock _l(mLock); return mHalWrapper->configureDirectChannel(sensorHandle, channelHandle, config); diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h index 80e77d96d4..747a6b0926 100644 --- a/services/sensorservice/SensorDevice.h +++ b/services/sensorservice/SensorDevice.h @@ -119,6 +119,7 @@ private: // HAL implementations. std::mutex mDynamicSensorsMutex; std::condition_variable mDynamicSensorsCv; + static constexpr std::chrono::seconds MAX_DYN_SENSOR_WAIT{5}; static const nsecs_t MINIMUM_EVENTS_PERIOD = 1000000; // 1000 Hz mutable Mutex mLock; // protect mActivationCount[].batchParams diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 5560ed738a..3e6d49f360 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -125,10 +125,7 @@ cc_defaults { thin: true, }, whole_program_vtables: true, // Requires ThinLTO - pgo: { - sampling: true, - profile_file: "surfaceflinger/surfaceflinger.profdata", - }, + afdo: true, // TODO(b/131771163): Fix broken fuzzer support with LTO. sanitize: { fuzzer: false, diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index 73770b7779..6cb12dda9f 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -173,6 +173,8 @@ public: // Sets the projection state to use virtual void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect, const Rect& orientedDisplaySpaceRect) = 0; + // Sets the brightness that will take effect next frame. + virtual void setNextBrightness(float brightness) = 0; // Sets the bounds to use virtual void setDisplaySize(const ui::Size&) = 0; // Gets the transform hint used in layers that belong to this output. Used to guide diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index 844876a997..a7a8e97be5 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -45,6 +45,7 @@ public: void setLayerCachingTexturePoolEnabled(bool) override; void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect, const Rect& orientedDisplaySpaceRect) override; + void setNextBrightness(float brightness) override; void setDisplaySize(const ui::Size&) override; void setLayerFilter(ui::LayerFilter) override; ui::Transform::RotationFlags getTransformHint() const override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h index c8f177b000..cc7c2574b7 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h @@ -133,6 +133,10 @@ struct OutputCompositionState { // White point of the client target float clientTargetWhitePointNits{-1.f}; + // Display brightness that will take effect this frame. + // This is slightly distinct from nits, in that nits cannot be passed to hw composer. + std::optional<float> displayBrightness = std::nullopt; + // Debugging void dump(std::string& result) const; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index 7b0d028c11..b68b95d07b 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -39,6 +39,7 @@ public: MOCK_METHOD1(setLayerCachingEnabled, void(bool)); MOCK_METHOD1(setLayerCachingTexturePoolEnabled, void(bool)); MOCK_METHOD3(setProjection, void(ui::Rotation, const Rect&, const Rect&)); + MOCK_METHOD1(setNextBrightness, void(float)); MOCK_METHOD1(setDisplaySize, void(const ui::Size&)); MOCK_CONST_METHOD0(getTransformHint, ui::Transform::RotationFlags()); diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 08dd22d84e..186e191447 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -226,6 +226,17 @@ void Display::chooseCompositionStrategy() { // Get any composition changes requested by the HWC device, and apply them. std::optional<android::HWComposer::DeviceRequestedChanges> changes; auto& hwc = getCompositionEngine().getHwComposer(); + if (const auto physicalDisplayId = PhysicalDisplayId::tryCast(*halDisplayId); + physicalDisplayId && getState().displayBrightness) { + const status_t result = + hwc.setDisplayBrightness(*physicalDisplayId, *getState().displayBrightness, + Hwc2::Composer::DisplayBrightnessOptions{ + .applyImmediately = false}) + .get(); + ALOGE_IF(result != NO_ERROR, "setDisplayBrightness failed for %s: %d, (%s)", + getName().c_str(), result, strerror(-result)); + } + if (status_t result = hwc.getDeviceCompositionChanges(*halDisplayId, anyLayersRequireClientComposition(), getState().earliestPresentTime, @@ -248,6 +259,8 @@ void Display::chooseCompositionStrategy() { auto& state = editState(); state.usesClientComposition = anyLayersRequireClientComposition(); state.usesDeviceComposition = !allLayersRequireClientComposition(); + // Clear out the display brightness now that it's been communicated to composer. + state.displayBrightness.reset(); } bool Display::getSkipColorTransform() const { diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 6833584e71..192ee047ee 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -197,6 +197,10 @@ void Output::setProjection(ui::Rotation orientation, const Rect& layerStackSpace dirtyEntireOutput(); } +void Output::setNextBrightness(float brightness) { + editState().displayBrightness = brightness; +} + void Output::setDisplaySize(const ui::Size& size) { mRenderSurface->setDisplaySize(size); diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index 8558a80d0d..7dd4c2187b 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -37,6 +37,7 @@ #include "MockHWC2.h" #include "MockHWComposer.h" #include "MockPowerAdvisor.h" +#include "ftl/future.h" #include <aidl/android/hardware/graphics/composer3/Composition.h> @@ -48,6 +49,7 @@ namespace { namespace hal = android::hardware::graphics::composer::hal; using testing::_; +using testing::ByMove; using testing::DoAll; using testing::Eq; using testing::InSequence; @@ -594,6 +596,38 @@ TEST_F(DisplayChooseCompositionStrategyTest, normalOperation) { EXPECT_TRUE(state.usesDeviceComposition); } +TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithDisplayBrightness) { + // Since two calls are made to anyLayersRequireClientComposition with different return + // values, use a Sequence to control the matching so the values are returned in a known + // order. + constexpr float kDisplayBrightness = 0.5f; + Sequence s; + EXPECT_CALL(*mDisplay, anyLayersRequireClientComposition()) + .InSequence(s) + .WillOnce(Return(true)); + EXPECT_CALL(*mDisplay, anyLayersRequireClientComposition()) + .InSequence(s) + .WillOnce(Return(false)); + EXPECT_CALL(mHwComposer, + setDisplayBrightness(DEFAULT_DISPLAY_ID, kDisplayBrightness, + Hwc2::Composer::DisplayBrightnessOptions{.applyImmediately = + false})) + .WillOnce(Return(ByMove(ftl::yield<status_t>(NO_ERROR)))); + + EXPECT_CALL(mHwComposer, + getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _)) + .WillOnce(Return(NO_ERROR)); + EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false)); + + mDisplay->setNextBrightness(kDisplayBrightness); + mDisplay->chooseCompositionStrategy(); + + auto& state = mDisplay->getState(); + EXPECT_FALSE(state.usesClientComposition); + EXPECT_TRUE(state.usesDeviceComposition); + EXPECT_FALSE(state.displayBrightness.has_value()); +} + TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) { android::HWComposer::DeviceRequestedChanges changes{ {{nullptr, Composition::CLIENT}}, diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h index a590e2a385..dc5c5c8fcf 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h @@ -83,7 +83,9 @@ public: MOCK_METHOD4(setDisplayContentSamplingEnabled, status_t(HalDisplayId, bool, uint8_t, uint64_t)); MOCK_METHOD4(getDisplayedContentSample, status_t(HalDisplayId, uint64_t, uint64_t, DisplayedFrameStats*)); - MOCK_METHOD2(setDisplayBrightness, std::future<status_t>(PhysicalDisplayId, float)); + MOCK_METHOD3(setDisplayBrightness, + std::future<status_t>(PhysicalDisplayId, float, + const Hwc2::Composer::DisplayBrightnessOptions&)); MOCK_METHOD2(getDisplayBrightnessSupport, status_t(PhysicalDisplayId, bool*)); MOCK_METHOD2(onHotplug, diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h index db4151b1a7..50adcfb827 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h @@ -39,11 +39,10 @@ public: MOCK_METHOD(bool, supportsPowerHintSession, (), (override)); MOCK_METHOD(bool, isPowerHintSessionRunning, (), (override)); MOCK_METHOD(void, setTargetWorkDuration, (int64_t targetDurationNanos), (override)); - MOCK_METHOD(void, setPowerHintSessionThreadIds, (const std::vector<int32_t>& threadIds), - (override)); MOCK_METHOD(void, sendActualWorkDuration, (int64_t actualDurationNanos, nsecs_t timestamp), (override)); MOCK_METHOD(void, enablePowerHint, (bool enabled), (override)); + MOCK_METHOD(bool, startPowerHintSession, (const std::vector<int32_t>& threadIds), (override)); }; } // namespace mock diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 6d96260de7..f7c75337ff 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -574,6 +574,17 @@ TEST_F(OutputTest, setRenderSurfaceResetsBounds) { EXPECT_EQ(Rect(newDisplaySize), mOutput->getState().framebufferSpace.getBoundsAsRect()); } +/** + * Output::setDisplayBrightness() + */ + +TEST_F(OutputTest, setNextBrightness) { + constexpr float kDisplayBrightness = 0.5f; + mOutput->setNextBrightness(kDisplayBrightness); + ASSERT_TRUE(mOutput->getState().displayBrightness.has_value()); + EXPECT_EQ(kDisplayBrightness, mOutput->getState().displayBrightness); +} + /* * Output::getDirtyRegion() */ diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 76bbe2c58f..a36ea72b9f 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -311,6 +311,22 @@ void DisplayDevice::setProjection(ui::Rotation orientation, Rect layerStackSpace orientedDisplaySpaceRect); } +void DisplayDevice::stageBrightness(float brightness) { + mStagedBrightness = brightness; +} + +void DisplayDevice::persistBrightness(bool needsComposite) { + if (needsComposite && mStagedBrightness && mBrightness != *mStagedBrightness) { + getCompositionDisplay()->setNextBrightness(*mStagedBrightness); + mBrightness = *mStagedBrightness; + } + mStagedBrightness = std::nullopt; +} + +std::optional<float> DisplayDevice::getStagedBrightness() const { + return mStagedBrightness; +} + ui::Transform::RotationFlags DisplayDevice::getPrimaryDisplayRotationFlags() { return sPrimaryDisplayRotationFlags; } diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 324145ef47..d2accaa217 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -99,6 +99,9 @@ public: void setLayerStack(ui::LayerStack); void setDisplaySize(int width, int height); void setProjection(ui::Rotation orientation, Rect viewport, Rect frame); + void stageBrightness(float brightness) REQUIRES(SF_MAIN_THREAD); + void persistBrightness(bool needsComposite) REQUIRES(SF_MAIN_THREAD); + bool isBrightnessStale() const REQUIRES(SF_MAIN_THREAD); void setFlags(uint32_t flags); ui::Rotation getPhysicalOrientation() const { return mPhysicalOrientation; } @@ -106,6 +109,7 @@ public: static ui::Transform::RotationFlags getPrimaryDisplayRotationFlags(); + std::optional<float> getStagedBrightness() const REQUIRES(SF_MAIN_THREAD); ui::Transform::RotationFlags getTransformHint() const; const ui::Transform& getTransform() const; const Rect& getLayerStackSpaceRect() const; @@ -271,6 +275,8 @@ private: hardware::graphics::composer::hal::PowerMode mPowerMode = hardware::graphics::composer::hal::PowerMode::OFF; DisplayModePtr mActiveMode; + std::optional<float> mStagedBrightness = std::nullopt; + float mBrightness = -1.f; const DisplayModes mSupportedModes; std::atomic<nsecs_t> mLastHwVsync = 0; diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp index 293a2b2c5c..571f4d7d9c 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp @@ -246,6 +246,7 @@ bool AidlComposer::isSupported(OptionalFeature feature) const { switch (feature) { case OptionalFeature::RefreshRateSwitching: case OptionalFeature::ExpectedPresentTime: + case OptionalFeature::DisplayBrightnessCommand: return true; } } @@ -906,13 +907,14 @@ Error AidlComposer::setLayerPerFrameMetadataBlobs( return Error::NONE; } -Error AidlComposer::setDisplayBrightness(Display display, float brightness) { - const auto status = - mAidlComposerClient->setDisplayBrightness(translate<int64_t>(display), brightness); - if (!status.isOk()) { - ALOGE("setDisplayBrightness failed %s", status.getDescription().c_str()); - return static_cast<Error>(status.getServiceSpecificError()); +Error AidlComposer::setDisplayBrightness(Display display, float brightness, + const DisplayBrightnessOptions& options) { + mWriter.setDisplayBrightness(translate<int64_t>(display), brightness); + + if (options.applyImmediately) { + return execute(); } + return Error::NONE; } diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h index 20afee5eb0..4784426bca 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h @@ -180,7 +180,8 @@ public: Error setLayerPerFrameMetadataBlobs( Display display, Layer layer, const std::vector<IComposerClient::PerFrameMetadataBlob>& metadata) override; - Error setDisplayBrightness(Display display, float brightness) override; + Error setDisplayBrightness(Display display, float brightness, + const DisplayBrightnessOptions& options) override; // Composer HAL 2.4 Error getDisplayCapabilities( diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index c93051e1be..7f986bc98c 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -78,6 +78,8 @@ public: enum class OptionalFeature { RefreshRateSwitching, ExpectedPresentTime, + // Whether setDisplayBrightness is able to be applied as part of a display command. + DisplayBrightnessCommand, }; virtual bool isSupported(OptionalFeature) const = 0; @@ -204,7 +206,20 @@ public: DisplayedFrameStats* outStats) = 0; virtual Error setLayerPerFrameMetadataBlobs( Display display, Layer layer, const std::vector<PerFrameMetadataBlob>& metadata) = 0; - virtual Error setDisplayBrightness(Display display, float brightness) = 0; + // Options for setting the display brightness + struct DisplayBrightnessOptions { + // If true, then immediately submits a brightness change request to composer. Otherwise, + // submission of the brightness change may be deferred until presenting the next frame. + // applyImmediately should only be false if OptionalFeature::DisplayBrightnessCommand is + // supported. + bool applyImmediately = true; + + bool operator==(const DisplayBrightnessOptions& other) const { + return applyImmediately == other.applyImmediately; + } + }; + virtual Error setDisplayBrightness(Display display, float brightness, + const DisplayBrightnessOptions& options) = 0; // Composer HAL 2.4 virtual Error getDisplayCapabilities( diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index cd36eea623..c1373f9f23 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -37,8 +37,6 @@ #include <iterator> #include <set> -#include "ComposerHal.h" - using aidl::android::hardware::graphics::composer3::Composition; using aidl::android::hardware::graphics::composer3::DisplayCapability; @@ -532,9 +530,10 @@ Error Display::presentOrValidate(nsecs_t expectedPresentTime, uint32_t* outNumTy return error; } -std::future<Error> Display::setDisplayBrightness(float brightness) { - return ftl::defer([composer = &mComposer, id = mId, brightness] { - const auto intError = composer->setDisplayBrightness(id, brightness); +std::future<Error> Display::setDisplayBrightness( + float brightness, const Hwc2::Composer::DisplayBrightnessOptions& options) { + return ftl::defer([composer = &mComposer, id = mId, brightness, options] { + const auto intError = composer->setDisplayBrightness(id, brightness, options); return static_cast<Error>(intError); }); } diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index f833393125..404cc33698 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -34,6 +34,7 @@ #include <unordered_set> #include <vector> +#include "ComposerHal.h" #include "Hal.h" #include <aidl/android/hardware/graphics/composer3/Composition.h> @@ -143,7 +144,7 @@ public: nsecs_t expectedPresentTime, uint32_t* outNumTypes, uint32_t* outNumRequests, android::sp<android::Fence>* outPresentFence, uint32_t* state) = 0; [[clang::warn_unused_result]] virtual std::future<hal::Error> setDisplayBrightness( - float brightness) = 0; + float brightness, const Hwc2::Composer::DisplayBrightnessOptions& options) = 0; [[clang::warn_unused_result]] virtual hal::Error setActiveConfigWithConstraints( hal::HWConfigId configId, const hal::VsyncPeriodChangeConstraints& constraints, hal::VsyncPeriodChangeTimeline* outTimeline) = 0; @@ -211,7 +212,8 @@ public: uint32_t* outNumRequests, android::sp<android::Fence>* outPresentFence, uint32_t* state) override; - std::future<hal::Error> setDisplayBrightness(float brightness) override; + std::future<hal::Error> setDisplayBrightness( + float brightness, const Hwc2::Composer::DisplayBrightnessOptions& options) override; hal::Error setActiveConfigWithConstraints(hal::HWConfigId configId, const hal::VsyncPeriodChangeConstraints& constraints, hal::VsyncPeriodChangeTimeline* outTimeline) override; diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 546e677e05..057db46104 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -782,12 +782,13 @@ status_t HWComposer::getDisplayedContentSample(HalDisplayId displayId, uint64_t return NO_ERROR; } -std::future<status_t> HWComposer::setDisplayBrightness(PhysicalDisplayId displayId, - float brightness) { +std::future<status_t> HWComposer::setDisplayBrightness( + PhysicalDisplayId displayId, float brightness, + const Hwc2::Composer::DisplayBrightnessOptions& options) { RETURN_IF_INVALID_DISPLAY(displayId, ftl::yield<status_t>(BAD_INDEX)); auto& display = mDisplayData[displayId].hwcDisplay; - return ftl::chain(display->setDisplayBrightness(brightness)) + return ftl::chain(display->setDisplayBrightness(brightness, options)) .then([displayId](hal::Error error) -> status_t { if (error == hal::Error::UNSUPPORTED) { RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION); diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 69adfcd3e0..4fae06d4d8 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -192,7 +192,9 @@ public: DisplayedFrameStats* outStats) = 0; // Sets the brightness of a display. - virtual std::future<status_t> setDisplayBrightness(PhysicalDisplayId, float brightness) = 0; + virtual std::future<status_t> setDisplayBrightness( + PhysicalDisplayId, float brightness, + const Hwc2::Composer::DisplayBrightnessOptions&) = 0; // Events handling --------------------------------------------------------- @@ -340,7 +342,9 @@ public: uint64_t maxFrames) override; status_t getDisplayedContentSample(HalDisplayId, uint64_t maxFrames, uint64_t timestamp, DisplayedFrameStats* outStats) override; - std::future<status_t> setDisplayBrightness(PhysicalDisplayId, float brightness) override; + std::future<status_t> setDisplayBrightness( + PhysicalDisplayId, float brightness, + const Hwc2::Composer::DisplayBrightnessOptions&) override; // Events handling --------------------------------------------------------- diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp index 1ce9ccbefa..fbfff6170f 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp @@ -161,6 +161,7 @@ bool HidlComposer::isSupported(OptionalFeature feature) const { case OptionalFeature::RefreshRateSwitching: return mClient_2_4 != nullptr; case OptionalFeature::ExpectedPresentTime: + case OptionalFeature::DisplayBrightnessCommand: return false; } } @@ -1013,7 +1014,8 @@ Error HidlComposer::setLayerPerFrameMetadataBlobs( return Error::NONE; } -Error HidlComposer::setDisplayBrightness(Display display, float brightness) { +Error HidlComposer::setDisplayBrightness(Display display, float brightness, + const DisplayBrightnessOptions&) { if (!mClient_2_3) { return Error::UNSUPPORTED; } diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h index 8b98334afe..33bfab9799 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h @@ -289,7 +289,8 @@ public: Error setLayerPerFrameMetadataBlobs( Display display, Layer layer, const std::vector<IComposerClient::PerFrameMetadataBlob>& metadata) override; - Error setDisplayBrightness(Display display, float brightness) override; + Error setDisplayBrightness(Display display, float brightness, + const DisplayBrightnessOptions& options) override; // Composer HAL 2.4 Error getDisplayCapabilities( diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp index 5c2390eb38..930ddea089 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp +++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp @@ -93,13 +93,6 @@ void PowerAdvisor::init() { void PowerAdvisor::onBootFinished() { mBootFinished.store(true); - { - std::lock_guard lock(mPowerHalMutex); - HalWrapper* halWrapper = getPowerHal(); - if (halWrapper != nullptr && usePowerHintSession()) { - mPowerHintSessionRunning = halWrapper->startPowerHintSession(); - } - } } void PowerAdvisor::setExpensiveRenderingExpected(DisplayId displayId, bool expected) { @@ -156,7 +149,6 @@ void PowerAdvisor::notifyDisplayUpdateImminent() { // checks both if it supports and if it's enabled bool PowerAdvisor::usePowerHintSession() { // uses cached value since the underlying support and flag are unlikely to change at runtime - ALOGE_IF(!mPowerHintEnabled.has_value(), "Power hint session cannot be used before boot!"); return mPowerHintEnabled.value_or(false) && supportsPowerHintSession(); } @@ -175,10 +167,7 @@ bool PowerAdvisor::isPowerHintSessionRunning() { } void PowerAdvisor::setTargetWorkDuration(int64_t targetDurationNanos) { - // we check "supports" here not "usePowerHintSession" because this needs to work - // before the session is actually running, and "use" will always fail before boot - // we store the values passed in before boot to start the session with during onBootFinished - if (!supportsPowerHintSession()) { + if (!usePowerHintSession()) { ALOGV("Power hint session target duration cannot be set, skipping"); return; } @@ -186,24 +175,7 @@ void PowerAdvisor::setTargetWorkDuration(int64_t targetDurationNanos) { std::lock_guard lock(mPowerHalMutex); HalWrapper* const halWrapper = getPowerHal(); if (halWrapper != nullptr) { - halWrapper->setTargetWorkDuration(targetDurationNanos); - } - } -} - -void PowerAdvisor::setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) { - // we check "supports" here not "usePowerHintSession" because this needs to wsork - // before the session is actually running, and "use" will always fail before boot. - // we store the values passed in before boot to start the session with during onBootFinished - if (!supportsPowerHintSession()) { - ALOGV("Power hint session thread ids cannot be set, skipping"); - return; - } - { - std::lock_guard lock(mPowerHalMutex); - HalWrapper* const halWrapper = getPowerHal(); - if (halWrapper != nullptr) { - halWrapper->setPowerHintSessionThreadIds(const_cast<std::vector<int32_t>&>(threadIds)); + halWrapper->setTargetWorkDuration(targetDurationNanos - kTargetSafetyMargin.count()); } } } @@ -227,6 +199,21 @@ void PowerAdvisor::enablePowerHint(bool enabled) { mPowerHintEnabled = enabled; } +bool PowerAdvisor::startPowerHintSession(const std::vector<int32_t>& threadIds) { + if (!usePowerHintSession()) { + ALOGI("Power hint session cannot be started, skipping"); + } + { + std::lock_guard lock(mPowerHalMutex); + HalWrapper* halWrapper = getPowerHal(); + if (halWrapper != nullptr && usePowerHintSession()) { + halWrapper->setPowerHintSessionThreadIds(threadIds); + mPowerHintSessionRunning = halWrapper->startPowerHintSession(); + } + } + return mPowerHintSessionRunning; +} + class HidlPowerHalWrapper : public PowerAdvisor::HalWrapper { public: HidlPowerHalWrapper(sp<V1_3::IPower> powerHal) : mPowerHal(std::move(powerHal)) {} @@ -307,11 +294,10 @@ public: mHasDisplayUpdateImminent = false; } - // This just gives a number not a binder status, so no .isOk() - mSupportsPowerHints = mPowerHal->getInterfaceVersion() >= 2; + mSupportsPowerHint = checkPowerHintSessionSupported(); - if (mSupportsPowerHints) { - mPowerHintQueue.reserve(MAX_QUEUE_SIZE); + if (mSupportsPowerHint) { + mPowerHintQueue.reserve(kMaxQueueSize); } } @@ -356,7 +342,14 @@ public: } // only version 2+ of the aidl supports power hint sessions, hidl has no support - bool supportsPowerHintSession() override { return mSupportsPowerHints; } + bool supportsPowerHintSession() override { return mSupportsPowerHint; } + + bool checkPowerHintSessionSupported() { + int64_t unused; + // Try to get preferred rate to determine if hint sessions are supported + // We check for isOk not EX_UNSUPPORTED_OPERATION to lump other errors + return mPowerHal->getHintSessionPreferredRate(&unused).isOk(); + } bool isPowerHintSessionRunning() override { return mPowerHintSession != nullptr; } @@ -382,38 +375,43 @@ public: } bool startPowerHintSession() override { - if (mPowerHintSession != nullptr || !mPowerHintTargetDuration.has_value() || - mPowerHintThreadIds.empty()) { + if (mPowerHintSession != nullptr || mPowerHintThreadIds.empty()) { ALOGV("Cannot start power hint session, skipping"); return false; } auto ret = mPowerHal->createHintSession(getpid(), static_cast<int32_t>(getuid()), - mPowerHintThreadIds, *mPowerHintTargetDuration, + mPowerHintThreadIds, mTargetDuration, &mPowerHintSession); if (!ret.isOk()) { ALOGW("Failed to start power hint session with error: %s", ret.exceptionToString(ret.exceptionCode()).c_str()); - // Indicate to the poweradvisor that this wrapper likely needs to be remade - mShouldReconnectHal = true; + } else { + mLastTargetDurationSent = mTargetDuration; } return isPowerHintSessionRunning(); } bool shouldSetTargetDuration(int64_t targetDurationNanos) { - if (!mLastTargetDurationSent.has_value()) { - return true; - } - // report if the change in target from our last submission to now exceeds the threshold return abs(1.0 - - static_cast<double>(*mLastTargetDurationSent) / + static_cast<double>(mLastTargetDurationSent) / static_cast<double>(targetDurationNanos)) >= - ALLOWED_TARGET_DEVIATION_PERCENT; + kAllowedTargetDeviationPercent; } void setTargetWorkDuration(int64_t targetDurationNanos) override { - mPowerHintTargetDuration = targetDurationNanos; - if (shouldSetTargetDuration(targetDurationNanos) && isPowerHintSessionRunning()) { + ATRACE_CALL(); + mTargetDuration = targetDurationNanos; + if (sTraceHintSessionData) ATRACE_INT64("Time target", targetDurationNanos); + if (!sNormalizeTarget && shouldSetTargetDuration(targetDurationNanos) && + isPowerHintSessionRunning()) { + if (mLastActualDurationSent.has_value()) { + // update the error term here since we are actually sending an update to powerhal + if (sTraceHintSessionData) + ATRACE_INT64("Target error term", + targetDurationNanos - *mLastActualDurationSent); + } + ALOGV("Sending target time: %lld ns", static_cast<long long>(targetDurationNanos)); mLastTargetDurationSent = targetDurationNanos; auto ret = mPowerHintSession->updateTargetWorkDuration(targetDurationNanos); if (!ret.isOk()) { @@ -426,23 +424,27 @@ public: bool shouldReportActualDurationsNow() { // report if we have never reported before or have exceeded the max queue size - if (!mLastMessageReported.has_value() || mPowerHintQueue.size() >= MAX_QUEUE_SIZE) { + if (!mLastActualDurationSent.has_value() || mPowerHintQueue.size() >= kMaxQueueSize) { return true; } + if (!mActualDuration.has_value()) { + return false; + } + // duration of most recent timing - const double mostRecentActualDuration = - static_cast<double>(mPowerHintQueue.back().durationNanos); + const double mostRecentActualDuration = static_cast<double>(*mActualDuration); // duration of the last timing actually reported to the powerhal - const double lastReportedActualDuration = - static_cast<double>(mLastMessageReported->durationNanos); + const double lastReportedActualDuration = static_cast<double>(*mLastActualDurationSent); // report if the change in duration from then to now exceeds the threshold return abs(1.0 - mostRecentActualDuration / lastReportedActualDuration) >= - ALLOWED_ACTUAL_DEVIATION_PERCENT; + kAllowedActualDeviationPercent; } void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timeStampNanos) override { + ATRACE_CALL(); + if (actualDurationNanos < 0 || !isPowerHintSessionRunning()) { ALOGV("Failed to send actual work duration, skipping"); return; @@ -450,13 +452,31 @@ public: WorkDuration duration; duration.durationNanos = actualDurationNanos; + mActualDuration = actualDurationNanos; + + // normalize the sent values to a pre-set target + if (sNormalizeTarget) { + duration.durationNanos += mLastTargetDurationSent - mTargetDuration; + } duration.timeStampNanos = timeStampNanos; mPowerHintQueue.push_back(duration); + long long targetNsec = mTargetDuration; + long long durationNsec = actualDurationNanos; + + if (sTraceHintSessionData) { + ATRACE_INT64("Measured duration", durationNsec); + ATRACE_INT64("Target error term", targetNsec - durationNsec); + } + + ALOGV("Sending actual work duration of: %lld on target: %lld with error: %lld", + durationNsec, targetNsec, targetNsec - durationNsec); + // This rate limiter queues similar duration reports to the powerhal into // batches to avoid excessive binder calls. The criteria to send a given batch // are outlined in shouldReportActualDurationsNow() if (shouldReportActualDurationsNow()) { + ALOGV("Sending hint update batch"); auto ret = mPowerHintSession->reportActualWorkDuration(mPowerHintQueue); if (!ret.isOk()) { ALOGW("Failed to report actual work durations with error: %s", @@ -464,7 +484,8 @@ public: mShouldReconnectHal = true; } mPowerHintQueue.clear(); - mLastMessageReported = duration; + // we save the non-normalized value here to detect % changes + mLastActualDurationSent = actualDurationNanos; } } @@ -472,32 +493,48 @@ public: std::vector<int32_t> getPowerHintSessionThreadIds() override { return mPowerHintThreadIds; } - std::optional<int64_t> getTargetWorkDuration() override { return mPowerHintTargetDuration; } + std::optional<int64_t> getTargetWorkDuration() override { return mTargetDuration; } private: - // max number of messages allowed in mPowerHintQueue before reporting is forced - static constexpr int32_t MAX_QUEUE_SIZE = 15; - // max percent the actual duration can vary without causing a report (eg: 0.1 = 10%) - static constexpr double ALLOWED_ACTUAL_DEVIATION_PERCENT = 0.1; - // max percent the target duration can vary without causing a report (eg: 0.05 = 5%) - static constexpr double ALLOWED_TARGET_DEVIATION_PERCENT = 0.05; - const sp<IPower> mPowerHal = nullptr; bool mHasExpensiveRendering = false; bool mHasDisplayUpdateImminent = false; - bool mShouldReconnectHal = false; // used to indicate an error state and need for reconstruction + // Used to indicate an error state and need for reconstruction + bool mShouldReconnectHal = false; // This is not thread safe, but is currently protected by mPowerHalMutex so it needs no lock sp<IPowerHintSession> mPowerHintSession = nullptr; + // Queue of actual durations saved to report std::vector<WorkDuration> mPowerHintQueue; - // halwrapper owns these values so we can init when we want and reconnect if broken - std::optional<int64_t> mPowerHintTargetDuration; + // The latest un-normalized values we have received for target and actual + int64_t mTargetDuration = kDefaultTarget; + std::optional<int64_t> mActualDuration; + // The list of thread ids, stored so we can restart the session from this class if needed std::vector<int32_t> mPowerHintThreadIds; - // keep track of the last messages sent for rate limiter change detection - std::optional<WorkDuration> mLastMessageReported; - std::optional<int64_t> mLastTargetDurationSent; - bool mSupportsPowerHints; + bool mSupportsPowerHint; + // Keep track of the last messages sent for rate limiter change detection + std::optional<int64_t> mLastActualDurationSent; + int64_t mLastTargetDurationSent = kDefaultTarget; + // Whether to normalize all the actual values as error terms relative to a constant target + // This saves a binder call by not setting the target, and should not affect the pid values + static const bool sNormalizeTarget; + // Whether we should emit ATRACE_INT data for hint sessions + static const bool sTraceHintSessionData; + // Max number of messages allowed in mPowerHintQueue before reporting is forced + static constexpr int32_t kMaxQueueSize = 15; + // Max percent the actual duration can vary without causing a report (eg: 0.1 = 10%) + static constexpr double kAllowedActualDeviationPercent = 0.1; + // Max percent the target duration can vary without causing a report (eg: 0.05 = 5%) + static constexpr double kAllowedTargetDeviationPercent = 0.05; + // Target used for init and normalization, the actual value does not really matter + static constexpr int64_t kDefaultTarget = 50000000; }; +const bool AidlPowerHalWrapper::sTraceHintSessionData = + base::GetBoolProperty(std::string("debug.sf.trace_hint_sessions"), false); + +const bool AidlPowerHalWrapper::sNormalizeTarget = + base::GetBoolProperty(std::string("debug.sf.normalize_hint_session_durations"), true); + PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() { static std::unique_ptr<HalWrapper> sHalWrapper = nullptr; static bool sHasHal = true; diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h index b8fd17d654..28d28f41eb 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h +++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h @@ -17,6 +17,7 @@ #pragma once #include <atomic> +#include <chrono> #include <unordered_set> #include <utils/Mutex.h> @@ -24,6 +25,8 @@ #include "../Scheduler/OneShotTimer.h" #include "DisplayIdentification.h" +using namespace std::chrono_literals; + namespace android { class SurfaceFlinger; @@ -44,9 +47,9 @@ public: virtual bool supportsPowerHintSession() = 0; virtual bool isPowerHintSessionRunning() = 0; virtual void setTargetWorkDuration(int64_t targetDurationNanos) = 0; - virtual void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) = 0; virtual void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timestamp) = 0; virtual void enablePowerHint(bool enabled) = 0; + virtual bool startPowerHintSession(const std::vector<int32_t>& threadIds) = 0; }; namespace impl { @@ -86,9 +89,9 @@ public: bool supportsPowerHintSession() override; bool isPowerHintSessionRunning() override; void setTargetWorkDuration(int64_t targetDurationNanos) override; - void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) override; void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timestamp) override; void enablePowerHint(bool enabled) override; + bool startPowerHintSession(const std::vector<int32_t>& threadIds) override; private: HalWrapper* getPowerHal() REQUIRES(mPowerHalMutex); @@ -100,6 +103,12 @@ private: std::optional<bool> mSupportsPowerHint; bool mPowerHintSessionRunning = false; + // An adjustable safety margin which moves the "target" earlier to allow flinger to + // go a bit over without dropping a frame, especially since we can't measure + // the exact time HWC finishes composition so "actual" durations are measured + // from the end of present() instead, which is a bit later. + static constexpr const std::chrono::nanoseconds kTargetSafetyMargin = 2ms; + std::unordered_set<DisplayId> mExpensiveDisplays; bool mNotifiedExpensiveRendering = false; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index d690ede655..63fbe78ed9 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -339,7 +339,6 @@ Dataspace SurfaceFlinger::defaultCompositionDataspace = Dataspace::V0_SRGB; ui::PixelFormat SurfaceFlinger::defaultCompositionPixelFormat = ui::PixelFormat::RGBA_8888; Dataspace SurfaceFlinger::wideColorGamutCompositionDataspace = Dataspace::V0_SRGB; ui::PixelFormat SurfaceFlinger::wideColorGamutCompositionPixelFormat = ui::PixelFormat::RGBA_8888; -bool SurfaceFlinger::enableSdrDimming; LatchUnsignaledConfig SurfaceFlinger::enableLatchUnsignaledConfig; std::string decodeDisplayColorSetting(DisplayColorSetting displayColorSetting) { @@ -503,9 +502,6 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI mRefreshRateOverlaySpinner = property_get_bool("sf.debug.show_refresh_rate_overlay_spinner", 0); - // Debug property overrides ro. property - enableSdrDimming = property_get_bool("debug.sf.enable_sdr_dimming", enable_sdr_dimming(false)); - enableLatchUnsignaledConfig = getLatchUnsignaledConfig(); mTransactionTracingEnabled = @@ -721,7 +717,6 @@ void SurfaceFlinger::bootFinished() { ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) ); mFlagManager = std::make_unique<android::FlagManager>(); - mPowerAdvisor.enablePowerHint(mFlagManager->use_adpf_cpu_hint()); mFrameTracer->initialize(); mFrameTimeline->onBootFinished(); @@ -751,7 +746,18 @@ void SurfaceFlinger::bootFinished() { } readPersistentProperties(); + std::optional<pid_t> renderEngineTid = getRenderEngine().getRenderEngineTid(); + std::vector<int32_t> tidList; + tidList.emplace_back(gettid()); + if (renderEngineTid.has_value()) { + tidList.emplace_back(*renderEngineTid); + } mPowerAdvisor.onBootFinished(); + mPowerAdvisor.enablePowerHint(mFlagManager->use_adpf_cpu_hint()); + if (mPowerAdvisor.usePowerHintSession()) { + mPowerAdvisor.startPowerHintSession(tidList); + } + mBootStage = BootStage::FINISHED; if (property_get_bool("sf.debug.show_refresh_rate_overlay", false)) { @@ -1669,6 +1675,17 @@ status_t SurfaceFlinger::getDisplayBrightnessSupport(const sp<IBinder>& displayT return NO_ERROR; } +bool SurfaceFlinger::hasVisibleHdrLayer(const sp<DisplayDevice>& display) { + bool hasHdrLayers = false; + mDrawingState.traverse([&, + compositionDisplay = display->getCompositionDisplay()](Layer* layer) { + hasHdrLayers |= (layer->isVisible() && + compositionDisplay->includesLayer(layer->getCompositionEngineLayerFE()) && + isHdrDataspace(layer->getDataSpace())); + }); + return hasHdrLayers; +} + status_t SurfaceFlinger::setDisplayBrightness(const sp<IBinder>& displayToken, const gui::DisplayBrightness& brightness) { if (!displayToken) { @@ -1678,13 +1695,30 @@ status_t SurfaceFlinger::setDisplayBrightness(const sp<IBinder>& displayToken, const char* const whence = __func__; return ftl::chain(mScheduler->schedule([=]() MAIN_THREAD { if (const auto display = getDisplayDeviceLocked(displayToken)) { - if (enableSdrDimming) { + const bool supportsDisplayBrightnessCommand = + getHwComposer().getComposer()->isSupported( + Hwc2::Composer::OptionalFeature::DisplayBrightnessCommand); + // If we support applying display brightness as a command, then we also support + // dimming SDR layers. + if (supportsDisplayBrightnessCommand) { display->getCompositionDisplay() ->setDisplayBrightness(brightness.sdrWhitePointNits, brightness.displayBrightnessNits); + MAIN_THREAD_GUARD(display->stageBrightness(brightness.displayBrightness)); + if (hasVisibleHdrLayer(display)) { + scheduleComposite(FrameHint::kNone); + } else { + scheduleCommit(FrameHint::kNone); + } + return ftl::yield<status_t>(OK); + } else { + return getHwComposer() + .setDisplayBrightness(display->getPhysicalId(), + brightness.displayBrightness, + Hwc2::Composer::DisplayBrightnessOptions{ + .applyImmediately = true}); } - return getHwComposer().setDisplayBrightness(display->getPhysicalId(), - brightness.displayBrightness); + } else { ALOGE("%s: Invalid display token %p", whence, displayToken.get()); return ftl::yield<status_t>(NAME_NOT_FOUND); @@ -1939,6 +1973,13 @@ nsecs_t SurfaceFlinger::calculateExpectedPresentTime(DisplayStatInfo stats) cons } bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime) { + MainThreadScopedGuard mainThreadGuard(SF_MAIN_THREAD); + // we set this once at the beginning of commit to ensure consistency throughout the whole frame + mPowerHintSessionData.sessionEnabled = mPowerAdvisor.usePowerHintSession(); + if (mPowerHintSessionData.sessionEnabled) { + mPowerHintSessionData.commitStart = systemTime(); + } + // calculate the expected present time once and use the cached // value throughout this frame to make sure all layers are // seeing this same value. @@ -1952,6 +1993,10 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected const nsecs_t lastScheduledPresentTime = mScheduledPresentTime; mScheduledPresentTime = expectedVsyncTime; + if (mPowerHintSessionData.sessionEnabled) { + mPowerAdvisor.setTargetWorkDuration(mExpectedPresentTime - + mPowerHintSessionData.commitStart); + } const auto vsyncIn = [&] { if (!ATRACE_ENABLED()) return 0.f; return (mExpectedPresentTime - systemTime()) / 1e6f; @@ -2014,7 +2059,10 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected // We received the present fence from the HWC, so we assume it successfully updated // the mode, hence we update SF. mSetActiveModePending = false; - ON_MAIN_THREAD(updateInternalStateWithChangedMode()); + { + Mutex::Autolock lock(mStateLock); + updateInternalStateWithChangedMode(); + } } if (framePending) { @@ -2079,18 +2127,23 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected { Mutex::Autolock _l(mStateLock); mScheduler->chooseRefreshRateForContent(); + setActiveModeInHwcIfNeeded(); } - ON_MAIN_THREAD(setActiveModeInHwcIfNeeded()); - updateCursorAsync(); updateInputFlinger(); + MAIN_THREAD_GUARD(persistDisplayBrightness(mustComposite)); + return mustComposite && CC_LIKELY(mBootStage != BootStage::BOOTLOADER); } void SurfaceFlinger::composite(nsecs_t frameTime) { ATRACE_CALL(); + MainThreadScopedGuard mainThreadGuard(SF_MAIN_THREAD); + if (mPowerHintSessionData.sessionEnabled) { + mPowerHintSessionData.compositeStart = systemTime(); + } compositionengine::CompositionRefreshArgs refreshArgs; const auto& displays = ON_MAIN_THREAD(mDisplays); @@ -2144,6 +2197,11 @@ void SurfaceFlinger::composite(nsecs_t frameTime) { const auto presentTime = systemTime(); mCompositionEngine->present(refreshArgs); + + if (mPowerHintSessionData.sessionEnabled) { + mPowerHintSessionData.presentEnd = systemTime(); + } + mTimeStats->recordFrameDuration(frameTime, systemTime()); mScheduler->onPostComposition(presentTime); @@ -2191,6 +2249,13 @@ void SurfaceFlinger::composite(nsecs_t frameTime) { if (mCompositionEngine->needsAnotherUpdate()) { scheduleCommit(FrameHint::kNone); } + + // calculate total render time for performance hinting if adpf cpu hint is enabled, + if (mPowerHintSessionData.sessionEnabled) { + const nsecs_t flingerDuration = + (mPowerHintSessionData.presentEnd - mPowerHintSessionData.commitStart); + mPowerAdvisor.sendActualWorkDuration(flingerDuration, mPowerHintSessionData.presentEnd); + } } void SurfaceFlinger::updateLayerGeometry() { @@ -3118,43 +3183,91 @@ void SurfaceFlinger::updateInputFlinger() { mInputWindowCommands.clear(); } +void SurfaceFlinger::persistDisplayBrightness(bool needsComposite) { + const bool supportsDisplayBrightnessCommand = getHwComposer().getComposer()->isSupported( + Hwc2::Composer::OptionalFeature::DisplayBrightnessCommand); + if (!supportsDisplayBrightnessCommand) { + return; + } + + const auto& displays = ON_MAIN_THREAD(mDisplays); + + for (const auto& [_, display] : displays) { + if (const auto brightness = display->getStagedBrightness(); brightness) { + if (!needsComposite) { + const status_t error = + getHwComposer() + .setDisplayBrightness(display->getPhysicalId(), *brightness, + Hwc2::Composer::DisplayBrightnessOptions{ + .applyImmediately = true}) + .get(); + + ALOGE_IF(error != NO_ERROR, + "Error setting display brightness for display %s: %d (%s)", + display->getDebugName().c_str(), error, strerror(error)); + } + display->persistBrightness(needsComposite); + } + } +} + void SurfaceFlinger::buildWindowInfos(std::vector<WindowInfo>& outWindowInfos, std::vector<DisplayInfo>& outDisplayInfos) { - std::unordered_map<uint32_t /*layerStackId*/, - std::pair<bool /* isSecure */, const ui::Transform>> - inputDisplayDetails; + struct Details { + Details(bool receivesInput, bool isSecure, const ui::Transform& transform, + const DisplayInfo& info) + : receivesInput(receivesInput), + isSecure(isSecure), + transform(std::move(transform)), + info(std::move(info)) {} + bool receivesInput; + bool isSecure; + ui::Transform transform; + DisplayInfo info; + }; + std::unordered_map<uint32_t /*layerStackId*/, Details> inputDisplayDetails; for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) { - if (!display->receivesInput()) { - continue; - } const uint32_t layerStackId = display->getLayerStack().id; const auto& [info, transform] = display->getInputInfo(); const auto& [it, emplaced] = - inputDisplayDetails.try_emplace(layerStackId, display->isSecure(), transform); - if (!emplaced) { - ALOGE("Multiple displays claim to accept input for the same layer stack: %u", - layerStackId); + inputDisplayDetails.try_emplace(layerStackId, display->receivesInput(), + display->isSecure(), transform, info); + if (emplaced) { continue; } - outDisplayInfos.emplace_back(info); + + // There is more than one display for the layerStack. In this case, the display that is + // configured to receive input takes precedence. + auto& details = it->second; + if (!display->receivesInput()) { + continue; + } + ALOGE_IF(details.receivesInput, + "Multiple displays claim to accept input for the same layer stack: %u", + layerStackId); + details.receivesInput = display->receivesInput(); + details.isSecure = display->isSecure(); + details.transform = std::move(transform); + details.info = std::move(info); } mDrawingState.traverseInReverseZOrder([&](Layer* layer) { if (!layer->needsInputInfo()) return; - bool isSecure = true; - ui::Transform displayTransform = ui::Transform(); - const uint32_t layerStackId = layer->getLayerStack().id; const auto it = inputDisplayDetails.find(layerStackId); - if (it != inputDisplayDetails.end()) { - const auto& [secure, transform] = it->second; - isSecure = secure; - displayTransform = transform; + if (it == inputDisplayDetails.end()) { + // Do not create WindowInfos for windows on displays that cannot receive input. + return; } - outWindowInfos.push_back(layer->fillInputInfo(displayTransform, isSecure)); + const auto& details = it->second; + outWindowInfos.push_back(layer->fillInputInfo(details.transform, details.isSecure)); }); + + for (const auto& [_, details] : inputDisplayDetails) { + outDisplayInfos.push_back(std::move(details.info)); + } } void SurfaceFlinger::updateCursorAsync() { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 2d1f9ba6cb..61cfb4e71a 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -252,10 +252,6 @@ public: static constexpr SkipInitializationTag SkipInitialization; - // Whether or not SDR layers should be dimmed to the desired SDR white point instead of - // being treated as native display brightness - static bool enableSdrDimming; - static LatchUnsignaledConfig enableLatchUnsignaledConfig; // must be called before clients can connect @@ -676,6 +672,9 @@ private: void setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode) REQUIRES(mStateLock); + // Returns true if the display has a visible HDR layer in its layer stack. + bool hasVisibleHdrLayer(const sp<DisplayDevice>& display) REQUIRES(mStateLock); + // Sets the desired display mode specs. status_t setDesiredDisplayModeSpecsInternal( const sp<DisplayDevice>& display, @@ -692,6 +691,7 @@ private: void updateLayerGeometry(); void updateInputFlinger(); + void persistDisplayBrightness(bool needsComposite) REQUIRES(SF_MAIN_THREAD); void buildWindowInfos(std::vector<gui::WindowInfo>& outWindowInfos, std::vector<gui::DisplayInfo>& outDisplayInfos); void commitInputWindowCommands() REQUIRES(mStateLock); @@ -1359,6 +1359,13 @@ private: float getLayerFramerate(nsecs_t now, int32_t id) const { return mScheduler->getLayerFramerate(now, id); } + + struct { + bool sessionEnabled = false; + nsecs_t commitStart; + nsecs_t compositeStart; + nsecs_t presentEnd; + } mPowerHintSessionData GUARDED_BY(SF_MAIN_THREAD); }; } // namespace android diff --git a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp index f6b0def2f7..027a15e3f6 100644 --- a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp +++ b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp @@ -85,7 +85,7 @@ public: sp<Fence> fence, CallbackHelper& callback, const ReleaseCallbackId& id, ReleaseBufferCallbackHelper& releaseCallback) { Transaction t; - t.setBuffer(layer, buffer, fence, id.framenumber, id, releaseCallback.getCallback()); + t.setBuffer(layer, buffer, fence, id.framenumber, releaseCallback.getCallback()); t.addTransactionCompletedCallback(callback.function, callback.getContext()); t.apply(); } @@ -300,7 +300,7 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_FrameDropping) { nsecs_t time = systemTime() + std::chrono::nanoseconds(100ms).count(); Transaction t; - t.setBuffer(layer, firstBuffer, std::nullopt, std::nullopt, firstBufferCallbackId, + t.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber, releaseCallback->getCallback()); t.addTransactionCompletedCallback(transactionCallback.function, transactionCallback.getContext()); @@ -316,7 +316,7 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_FrameDropping) { // Dropping frames in transaction queue emits a callback sp<GraphicBuffer> secondBuffer = getBuffer(); ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber()); - t.setBuffer(layer, secondBuffer, std::nullopt, std::nullopt, secondBufferCallbackId, + t.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber, releaseCallback->getCallback()); t.addTransactionCompletedCallback(transactionCallback.function, transactionCallback.getContext()); @@ -360,7 +360,7 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_Merge_Different_Processes) { Transaction transaction1; transaction1.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber, - secondBufferCallbackId, releaseCallback->getCallback()); + releaseCallback->getCallback()); transaction1.addTransactionCompletedCallback(callback1.function, callback1.getContext()); // Set a different TransactionCompletedListener to mimic a second process @@ -395,14 +395,14 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_SetBuffer_OverwriteBuffers) { // Create transaction with a buffer. Transaction transaction; transaction.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber, - firstBufferCallbackId, releaseCallback->getCallback()); + releaseCallback->getCallback()); sp<GraphicBuffer> secondBuffer = getBuffer(); ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber()); // Call setBuffer on the same transaction with a different buffer. transaction.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber, - secondBufferCallbackId, releaseCallback->getCallback()); + releaseCallback->getCallback()); ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId)); } @@ -417,7 +417,7 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_Merge_Transactions_OverwriteBuffers) // Create transaction with a buffer. Transaction transaction1; transaction1.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber, - firstBufferCallbackId, releaseCallback->getCallback()); + releaseCallback->getCallback()); sp<GraphicBuffer> secondBuffer = getBuffer(); ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber()); @@ -425,7 +425,7 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_Merge_Transactions_OverwriteBuffers) // Create a second transaction with a new buffer for the same layer. Transaction transaction2; transaction2.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber, - secondBufferCallbackId, releaseCallback->getCallback()); + releaseCallback->getCallback()); // merge transaction1 into transaction2 so ensure we get a proper buffer release callback. transaction1.merge(std::move(transaction2)); @@ -446,7 +446,7 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_MergeBuffers_Different_Processes) { Transaction transaction1; transaction1.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber, - firstBufferCallbackId, releaseCallback->getCallback()); + releaseCallback->getCallback()); // Sent a second buffer to allow the first buffer to get released. sp<GraphicBuffer> secondBuffer = getBuffer(); @@ -454,7 +454,7 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_MergeBuffers_Different_Processes) { Transaction transaction2; transaction2.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber, - secondBufferCallbackId, releaseCallback->getCallback()); + releaseCallback->getCallback()); // Set a different TransactionCompletedListener to mimic a second process TransactionCompletedListener::setInstance(secondCompletedListener); diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 55684187f8..bba880ec90 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -55,6 +55,7 @@ cc_test { "DisplayTransactionTest.cpp", "DisplayDevice_GetBestColorModeTest.cpp", "DisplayDevice_InitiateModeChange.cpp", + "DisplayDevice_SetDisplayBrightnessTest.cpp", "DisplayDevice_SetProjectionTest.cpp", "EventThreadTest.cpp", "FlagManagerTest.cpp", diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp new file mode 100644 index 0000000000..73c60e1035 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp @@ -0,0 +1,99 @@ +/* + * Copyright 2021 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. + */ + +#undef LOG_TAG +#define LOG_TAG "LibSurfaceFlingerUnittests" + +#include "DisplayTransactionTestHelpers.h" + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +namespace android { +namespace { + +using hal::RenderIntent; + +using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector; + +class SetDisplayBrightnessTest : public DisplayTransactionTest { +public: + sp<DisplayDevice> getDisplayDevice() { return injectDefaultInternalDisplay({}); } +}; + +TEST_F(SetDisplayBrightnessTest, persistDisplayBrightnessNoComposite) { + MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD); + sp<DisplayDevice> displayDevice = getDisplayDevice(); + + EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness()); + + constexpr float kDisplayBrightness = 0.5f; + displayDevice->stageBrightness(kDisplayBrightness); + + EXPECT_EQ(0.5f, displayDevice->getStagedBrightness()); + + displayDevice->persistBrightness(false); + + EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness()); + EXPECT_EQ(std::nullopt, displayDevice->getCompositionDisplay()->getState().displayBrightness); +} + +TEST_F(SetDisplayBrightnessTest, persistDisplayBrightnessWithComposite) { + MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD); + sp<DisplayDevice> displayDevice = getDisplayDevice(); + + EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness()); + + constexpr float kDisplayBrightness = 0.5f; + displayDevice->stageBrightness(kDisplayBrightness); + + EXPECT_EQ(0.5f, displayDevice->getStagedBrightness()); + + displayDevice->persistBrightness(true); + + EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness()); + EXPECT_EQ(kDisplayBrightness, + displayDevice->getCompositionDisplay()->getState().displayBrightness); +} + +TEST_F(SetDisplayBrightnessTest, persistDisplayBrightnessWithCompositeShortCircuitsOnNoOp) { + MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD); + sp<DisplayDevice> displayDevice = getDisplayDevice(); + + EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness()); + + constexpr float kDisplayBrightness = 0.5f; + displayDevice->stageBrightness(kDisplayBrightness); + + EXPECT_EQ(0.5f, displayDevice->getStagedBrightness()); + + displayDevice->persistBrightness(true); + + EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness()); + EXPECT_EQ(kDisplayBrightness, + displayDevice->getCompositionDisplay()->getState().displayBrightness); + displayDevice->getCompositionDisplay()->editState().displayBrightness = std::nullopt; + + displayDevice->stageBrightness(kDisplayBrightness); + EXPECT_EQ(0.5f, displayDevice->getStagedBrightness()); + displayDevice->persistBrightness(true); + + EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness()); + EXPECT_EQ(std::nullopt, displayDevice->getCompositionDisplay()->getState().displayBrightness); +} + +} // namespace +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index b1f704a48b..c318e28ffe 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -60,6 +60,7 @@ DisplayTransactionTest::~DisplayTransactionTest() { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); + mFlinger.resetScheduler(nullptr); } void DisplayTransactionTest::injectMockScheduler() { diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 0067997398..361d629f1e 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -347,6 +347,11 @@ public: auto notifyPowerBoost(int32_t boostId) { return mFlinger->notifyPowerBoost(boostId); } + auto setDisplayBrightness(const sp<IBinder>& display, + const gui::DisplayBrightness& brightness) { + return mFlinger->setDisplayBrightness(display, brightness); + } + // Allow reading display state without locking, as if called on the SF main thread. auto setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode) NO_THREAD_SAFETY_ANALYSIS { diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h index a2492e2acd..ec15a21f0e 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h @@ -120,7 +120,7 @@ public: Error(Display, uint64_t, uint64_t, DisplayedFrameStats*)); MOCK_METHOD3(setLayerPerFrameMetadataBlobs, Error(Display, Layer, const std::vector<IComposerClient::PerFrameMetadataBlob>&)); - MOCK_METHOD2(setDisplayBrightness, Error(Display, float)); + MOCK_METHOD3(setDisplayBrightness, Error(Display, float, const DisplayBrightnessOptions&)); MOCK_METHOD2( getDisplayCapabilities, Error(Display, diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h index cb1009f0db..c3b19c1ddd 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h @@ -80,7 +80,8 @@ public: MOCK_METHOD(hal::Error, presentOrValidate, (nsecs_t, uint32_t *, uint32_t *, android::sp<android::Fence> *, uint32_t *), (override)); - MOCK_METHOD(std::future<hal::Error>, setDisplayBrightness, (float), (override)); + MOCK_METHOD(std::future<hal::Error>, setDisplayBrightness, + (float, const Hwc2::Composer::DisplayBrightnessOptions &), (override)); MOCK_METHOD(hal::Error, setActiveConfigWithConstraints, (hal::HWConfigId, const hal::VsyncPeriodChangeConstraints &, hal::VsyncPeriodChangeTimeline *), diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h index 23b849a737..c598cbc28e 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h @@ -37,11 +37,10 @@ public: MOCK_METHOD(bool, supportsPowerHintSession, (), (override)); MOCK_METHOD(bool, isPowerHintSessionRunning, (), (override)); MOCK_METHOD(void, setTargetWorkDuration, (int64_t targetDurationNanos), (override)); - MOCK_METHOD(void, setPowerHintSessionThreadIds, (const std::vector<int32_t>& threadIds), - (override)); MOCK_METHOD(void, sendActualWorkDuration, (int64_t actualDurationNanos, nsecs_t timestamp), (override)); MOCK_METHOD(void, enablePowerHint, (bool enabled), (override)); + MOCK_METHOD(bool, startPowerHintSession, (const std::vector<int32_t>& threadIds), (override)); }; } // namespace android::Hwc2::mock diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h index 8b48e1c16d..0840a2f77c 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h +++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h @@ -34,6 +34,7 @@ public: MOCK_METHOD0(createClone, sp<Layer>()); MOCK_CONST_METHOD0(getFrameRateForLayerTree, FrameRate()); MOCK_CONST_METHOD0(getOwnerUid, uid_t()); + MOCK_CONST_METHOD0(getDataSpace, ui::Dataspace()); }; } // namespace android::mock |