Merge changes from topic "sensors-hal-aidl"
* changes:
Adds AIDL sensors HAL crash handling
Add AidlSensorHalWrapper code
Refactor dynamic sensors logic
Reorganize sensors resolution logic
Fix sp ownership in HidlSensorHalWrapper
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index d4c17fe..289c2ae 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -1602,6 +1602,7 @@
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
auto data_path = create_data_path(uuid_);
auto noop = (flags & FLAG_FREE_CACHE_NOOP);
+ auto defy_target = (flags & FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES);
int64_t free = data_disk_free(data_path);
if (free < 0) {
@@ -1610,11 +1611,13 @@
int64_t cleared = 0;
int64_t needed = targetFreeBytes - free;
- LOG(DEBUG) << "Device " << data_path << " has " << free << " free; requested "
- << targetFreeBytes << "; needed " << needed;
+ if (!defy_target) {
+ LOG(DEBUG) << "Device " << data_path << " has " << free << " free; requested "
+ << targetFreeBytes << "; needed " << needed;
- if (free >= targetFreeBytes) {
- return ok();
+ if (free >= targetFreeBytes) {
+ return ok();
+ }
}
if (flags & FLAG_FREE_CACHE_V2) {
@@ -1739,15 +1742,17 @@
cleared += item->size;
}
- // Verify that we're actually done before bailing, since sneaky
- // apps might be using hardlinks
- if (needed <= 0) {
- free = data_disk_free(data_path);
- needed = targetFreeBytes - free;
+ if (!defy_target) {
+ // Verify that we're actually done before bailing, since sneaky
+ // apps might be using hardlinks
if (needed <= 0) {
- break;
- } else {
- LOG(WARNING) << "Expected to be done but still need " << needed;
+ free = data_disk_free(data_path);
+ needed = targetFreeBytes - free;
+ if (needed <= 0) {
+ break;
+ } else {
+ LOG(WARNING) << "Expected to be done but still need " << needed;
+ }
}
}
}
@@ -1757,12 +1762,16 @@
return error("Legacy cache logic no longer supported");
}
- free = data_disk_free(data_path);
- if (free >= targetFreeBytes) {
- return ok();
+ if (!defy_target) {
+ free = data_disk_free(data_path);
+ if (free >= targetFreeBytes) {
+ return ok();
+ } else {
+ return error(StringPrintf("Failed to free up %" PRId64 " on %s; final free space %" PRId64,
+ targetFreeBytes, data_path.c_str(), free));
+ }
} else {
- return error(StringPrintf("Failed to free up %" PRId64 " on %s; final free space %" PRId64,
- targetFreeBytes, data_path.c_str(), free));
+ return ok();
}
}
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index e024548..684a311 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -140,6 +140,8 @@
const int FLAG_FREE_CACHE_V2 = 0x100;
const int FLAG_FREE_CACHE_V2_DEFY_QUOTA = 0x200;
const int FLAG_FREE_CACHE_NOOP = 0x400;
+ // Set below flag to clear cache irrespective of target free bytes required
+ const int FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES = 0x800;
const int FLAG_USE_QUOTA = 0x1000;
const int FLAG_FORCE = 0x2000;
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 6aa32b8..e978e79 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -140,8 +140,8 @@
PrepareEnvironmentVariables();
- if (!EnsureBootImageAndDalvikCache()) {
- LOG(ERROR) << "Bad boot image.";
+ if (!EnsureDalvikCache()) {
+ LOG(ERROR) << "Bad dalvik cache.";
return 5;
}
@@ -349,8 +349,8 @@
}
}
- // 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 @@
}
}
- // 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 b661684..51c4589 100644
--- a/cmds/installd/run_dex2oat.cpp
+++ b/cmds/installd/run_dex2oat.cpp
@@ -50,10 +50,6 @@
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 @@
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 @@
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 475e124..559244f 100644
--- a/cmds/installd/run_dex2oat.h
+++ b/cmds/installd/run_dex2oat.h
@@ -50,13 +50,13 @@
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 0a638cd..2a8135a 100644
--- a/cmds/installd/run_dex2oat_test.cpp
+++ b/cmds/installd/run_dex2oat_test.cpp
@@ -114,7 +114,7 @@
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 @@
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 @@
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 @@
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 @@
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/cmds/installd/tests/installd_cache_test.cpp b/cmds/installd/tests/installd_cache_test.cpp
index 8a27a06..4976646 100644
--- a/cmds/installd/tests/installd_cache_test.cpp
+++ b/cmds/installd/tests/installd_cache_test.cpp
@@ -42,6 +42,7 @@
#define FLAG_FREE_CACHE_V2 InstalldNativeService::FLAG_FREE_CACHE_V2
#define FLAG_FREE_CACHE_V2_DEFY_QUOTA InstalldNativeService::FLAG_FREE_CACHE_V2_DEFY_QUOTA
+#define FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES InstalldNativeService::FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES
int get_property(const char *key, char *value, const char *default_value) {
return property_get(key, value, default_value);
@@ -181,6 +182,35 @@
EXPECT_EQ(0, exists("com.example/cache/foo/two"));
}
+TEST_F(CacheTest, FreeCache_DefyTargetFreeBytes) {
+ LOG(INFO) << "FreeCache_DefyTargetFreeBytes";
+
+ mkdir("com.example");
+ touch("com.example/normal", 1 * kMbInBytes, 60);
+ mkdir("com.example/cache");
+ mkdir("com.example/cache/foo");
+ touch("com.example/cache/foo/one", 65 * kMbInBytes, 60);
+ touch("com.example/cache/foo/two", 2 * kMbInBytes, 120);
+
+ EXPECT_EQ(0, exists("com.example/normal"));
+ EXPECT_EQ(0, exists("com.example/cache/foo/one"));
+ EXPECT_EQ(0, exists("com.example/cache/foo/two"));
+
+ service->freeCache(testUuid, kMbInBytes, FLAG_FREE_CACHE_V2
+ | FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES);
+
+ EXPECT_EQ(0, exists("com.example/normal"));
+ EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
+ EXPECT_EQ(0, exists("com.example/cache/foo/two"));
+
+ service->freeCache(testUuid, kMbInBytes, FLAG_FREE_CACHE_V2
+ | FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES);
+
+ EXPECT_EQ(0, exists("com.example/normal"));
+ EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
+ EXPECT_EQ(0, exists("com.example/cache/foo/two"));
+}
+
TEST_F(CacheTest, FreeCache_Age) {
LOG(INFO) << "FreeCache_Age";
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 0000000..0a11835
--- /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 0000000..8deebc0
--- /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 e1cacac..ddff144 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -382,7 +382,6 @@
// 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 @@
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 @@
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/libs/binder/Android.bp b/libs/binder/Android.bp
index d8101fa..b2ea441 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -202,7 +202,6 @@
sanitize: {
misc_undefined: ["integer"],
},
- min_sdk_version: "30",
tidy: true,
tidy_flags: [
@@ -225,10 +224,7 @@
"portability*",
],
- pgo: {
- sampling: true,
- profile_file: "libbinder/libbinder.profdata",
- },
+ afdo: true,
}
cc_defaults {
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 55d3d70..13f0a4c 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -352,11 +352,6 @@
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/Parcel.cpp b/libs/binder/Parcel.cpp
index ba57a98..f84f639 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -739,6 +739,17 @@
}
}
+binder::Status Parcel::enforceNoDataAvail() const {
+ const auto n = dataAvail();
+ if (n == 0) {
+ return binder::Status::ok();
+ }
+ return binder::Status::
+ fromExceptionCode(binder::Status::Exception::EX_BAD_PARCELABLE,
+ String8::format("Parcel data not fully consumed, unread size: %zu",
+ n));
+}
+
size_t Parcel::objectsCount() const
{
return mObjectsSize;
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index 93ed50e..ace5cd5 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -287,8 +287,8 @@
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 @@
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 @@
.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 a5a2bb1..b84395e 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -615,8 +615,9 @@
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 @@
}
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 09b3d68..6286c9c 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 @@
}
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::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 @@
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 @@
.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 @@
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 @@
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 @@
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 @@
.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 @@
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 @@
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 @@
.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 @@
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 dba0a43..5cad394 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 @@
};
[[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 7669518..2182e18 100644
--- a/libs/binder/RpcTransportRaw.cpp
+++ b/libs/binder/RpcTransportRaw.cpp
@@ -43,12 +43,10 @@
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 @@
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 @@
}
}
- 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 7f810b1..c05ea15 100644
--- a/libs/binder/RpcTransportTls.cpp
+++ b/libs/binder/RpcTransportTls.cpp
@@ -275,9 +275,9 @@
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 @@
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/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index 82bebc9..bf02099 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -54,8 +54,6 @@
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/Parcel.h b/libs/binder/include/binder/Parcel.h
index 8dbdc1d..450e388 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -54,6 +54,9 @@
class RpcSession;
class String8;
class TextOutput;
+namespace binder {
+class Status;
+}
class Parcel {
friend class IPCThreadState;
@@ -131,6 +134,10 @@
IPCThreadState* threadState = nullptr) const;
bool checkInterface(IBinder*) const;
+ // Verify there are no bytes left to be read on the Parcel.
+ // Returns Status(EX_BAD_PARCELABLE) when the Parcel is not consumed.
+ binder::Status enforceNoDataAvail() const;
+
void freeData();
size_t objectsCount() const;
diff --git a/libs/binder/include/binder/RpcTransport.h b/libs/binder/include/binder/RpcTransport.h
index db8b5e9..348bfeb 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 @@
/**
* 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 @@
* 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/include_platform/android/binder_ibinder_platform.h b/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h
index 0549198..89f21dd 100644
--- a/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h
+++ b/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h
@@ -74,6 +74,7 @@
* This must be called before the object is sent to another process. Not thread
* safe.
*
+ * \param binder local server binder to set the policy for
* \param inheritRt whether to inherit realtime scheduling policies (default is
* false).
*/
diff --git a/libs/binder/tests/binderParcelUnitTest.cpp b/libs/binder/tests/binderParcelUnitTest.cpp
index 4950b23..aee15d8 100644
--- a/libs/binder/tests/binderParcelUnitTest.cpp
+++ b/libs/binder/tests/binderParcelUnitTest.cpp
@@ -16,15 +16,17 @@
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
+#include <binder/Status.h>
#include <cutils/ashmem.h>
#include <gtest/gtest.h>
using android::IPCThreadState;
using android::OK;
using android::Parcel;
+using android::status_t;
using android::String16;
using android::String8;
-using android::status_t;
+using android::binder::Status;
TEST(Parcel, NonNullTerminatedString8) {
String8 kTestString = String8("test-is-good");
@@ -60,6 +62,19 @@
EXPECT_EQ(output.size(), 0);
}
+TEST(Parcel, EnforceNoDataAvail) {
+ const int32_t kTestInt = 42;
+ const String8 kTestString = String8("test-is-good");
+ Parcel p;
+ p.writeInt32(kTestInt);
+ p.writeString8(kTestString);
+ p.setDataPosition(0);
+ EXPECT_EQ(kTestInt, p.readInt32());
+ EXPECT_EQ(p.enforceNoDataAvail().exceptionCode(), Status::Exception::EX_BAD_PARCELABLE);
+ EXPECT_EQ(kTestString, p.readString8());
+ EXPECT_EQ(p.enforceNoDataAvail().exceptionCode(), Status::Exception::EX_NONE);
+}
+
// Tests a second operation results in a parcel at the same location as it
// started.
void parcelOpSameLength(const std::function<void(Parcel*)>& a, const std::function<void(Parcel*)>& b) {
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 5a96b78..ca68b99 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -1674,8 +1674,8 @@
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 @@
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 @@
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 @@
}
}
- 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/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp
index 077d915..13f7195 100644
--- a/libs/binder/tests/parcel_fuzzer/binder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder.cpp
@@ -22,6 +22,7 @@
#include <android/os/IServiceManager.h>
#include <binder/ParcelableHolder.h>
#include <binder/PersistableBundle.h>
+#include <binder/Status.h>
using ::android::status_t;
using ::android::base::HexString;
@@ -100,6 +101,7 @@
PARCEL_READ_NO_STATUS(size_t, dataAvail),
PARCEL_READ_NO_STATUS(size_t, dataPosition),
PARCEL_READ_NO_STATUS(size_t, dataCapacity),
+ PARCEL_READ_NO_STATUS(::android::binder::Status, enforceNoDataAvail),
[] (const ::android::Parcel& p, uint8_t pos) {
FUZZ_LOG() << "about to setDataPosition: " << pos;
p.setDataPosition(pos);
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index c5dec19..ec3587b 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -66,6 +66,7 @@
host_supported: true,
srcs: [
":guiconstants_aidl",
+ ":inputconstants_aidl",
"android/gui/DisplayInfo.aidl",
"android/gui/FocusRequest.aidl",
"android/gui/InputApplicationInfo.aidl",
@@ -248,10 +249,7 @@
"libpdx_headers",
],
- pgo: {
- sampling: true,
- profile_file: "libgui/libgui.profdata",
- },
+ afdo: true,
lto: {
thin: true,
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 85a4b67..34faf87 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -164,8 +164,7 @@
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,
@@ -182,14 +181,14 @@
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 +196,20 @@
}
SurfaceComposerClient::Transaction t;
- const bool setBackpressureFlag = !SurfaceControl::isSameSurface(mSurfaceControl, surface);
+ const bool surfaceControlChanged = !SurfaceControl::isSameSurface(mSurfaceControl, surface);
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) {
+ BQA_LOGD("Updating SurfaceControl without recreating BBQ");
+ 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 +223,9 @@
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;
}
}
@@ -640,7 +636,7 @@
// add to shadow queue
mNumFrameAvailable++;
- if (mWaitForTransactionCallback && mNumFrameAvailable == 2) {
+ if (mWaitForTransactionCallback && mNumFrameAvailable >= 2) {
acquireAndReleaseBuffer();
}
ATRACE_INT(mQueuedBufferTrace.c_str(),
@@ -717,7 +713,7 @@
// 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 +987,54 @@
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->setBlastBufferQueue(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/WindowInfo.cpp b/libs/gui/WindowInfo.cpp
index 5f3a726..8d356aa 100644
--- a/libs/gui/WindowInfo.cpp
+++ b/libs/gui/WindowInfo.cpp
@@ -43,6 +43,14 @@
return flags.test(Flag::SPLIT_TOUCH);
}
+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 8a2f392..8b2310d 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -82,6 +82,7 @@
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 +110,7 @@
uint32_t getLastTransformHint() const;
uint64_t getLastAcquiredFrameNum();
+ void abandon();
virtual ~BLASTBufferQueue();
@@ -145,15 +147,15 @@
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/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h
index 54a372c..2bfaec8 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,12 +132,23 @@
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,
+ // 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
@@ -215,6 +227,10 @@
bool supportsSplitTouch() const;
+ 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 48b8621..42a32f3 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -1069,6 +1069,94 @@
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 f960e07..6f1263b 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 @@
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 @@
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 @@
});
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, 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 f0b97a7..84dba84 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -344,11 +344,6 @@
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/android/os/IInputConstants.aidl b/libs/input/android/os/IInputConstants.aidl
index 474a1e4..63bf23d 100644
--- a/libs/input/android/os/IInputConstants.aidl
+++ b/libs/input/android/os/IInputConstants.aidl
@@ -53,4 +53,53 @@
* 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/ui/Android.bp b/libs/ui/Android.bp
index 936e653..006c478 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -227,10 +227,7 @@
],
min_sdk_version: "29",
- pgo: {
- sampling: true,
- profile_file: "libui/libui.profdata",
- },
+ afdo: true,
}
cc_library_headers {
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 8cdb706..469c9e6 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -24,6 +24,7 @@
cc_defaults {
name: "inputflinger_defaults",
+ cpp_std: "c++20",
cflags: [
"-Wall",
"-Wextra",
diff --git a/services/inputflinger/BlockingQueue.h b/services/inputflinger/BlockingQueue.h
index b612ca7..8300e8a 100644
--- a/services/inputflinger/BlockingQueue.h
+++ b/services/inputflinger/BlockingQueue.h
@@ -71,8 +71,7 @@
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/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index 936ecf9..8046bbe 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -214,7 +214,7 @@
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 @@
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 477781a..0f79296 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -184,8 +184,7 @@
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 b0fa678..f190f67 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -91,7 +91,6 @@
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 +377,7 @@
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;
@@ -506,12 +505,6 @@
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 +523,14 @@
}
// 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 +541,12 @@
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 ---
@@ -939,8 +940,10 @@
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,20 +1048,21 @@
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) {
LOG_ALWAYS_FATAL("Must provide a valid touch state if adding outside targets");
}
// Traverse windows from front to back to find touched window.
- const std::vector<sp<WindowInfoHandle>>& windowHandles = getWindowHandlesLocked(displayId);
+ const auto& windowHandles = getWindowHandlesLocked(displayId);
for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {
if (ignoreDragWindow && haveSameToken(windowHandle, mDragState->dragWindow)) {
continue;
}
const WindowInfo& info = *windowHandle->getInfo();
- if (windowAcceptsTouchAt(info, displayId, x, y)) {
+ if (!info.isSpy() && windowAcceptsTouchAt(info, displayId, x, y, isStylus)) {
return windowHandle;
}
@@ -1070,6 +1074,26 @@
return nullptr;
}
+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, isStylus)) {
+ continue;
+ }
+ if (!info.isSpy()) {
+ // The first touched non-spy window was found, so return the spy windows touched so far.
+ return spyWindows;
+ }
+ spyWindows.push_back(windowHandle);
+ }
+ return spyWindows;
+}
+
void InputDispatcher::dropInboundEventLocked(const EventEntry& entry, DropReason dropReason) {
const char* reason;
switch (dropReason) {
@@ -2041,8 +2065,9 @@
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) {
@@ -2078,9 +2103,11 @@
}
}
- std::vector<sp<WindowInfoHandle>> newTouchedWindows;
+ std::vector<sp<WindowInfoHandle>> newTouchedWindows =
+ findTouchedSpyWindowsAtLocked(displayId, x, y, isStylus);
if (newTouchedWindowHandle != nullptr) {
- newTouchedWindows.push_back(newTouchedWindowHandle);
+ // Process the foreground window first so that it is the first to receive the event.
+ newTouchedWindows.insert(newTouchedWindows.begin(), newTouchedWindowHandle);
}
for (const sp<WindowInfoHandle>& windowHandle : newTouchedWindows) {
@@ -2128,8 +2155,10 @@
// Set target flags.
int32_t targetFlags = InputTarget::FLAG_DISPATCH_AS_IS;
- // There should only be one new foreground (non-spy) window at this location.
- targetFlags |= InputTarget::FLAG_FOREGROUND;
+ if (!info.isSpy()) {
+ // There should only be one new foreground (non-spy) window at this location.
+ targetFlags |= InputTarget::FLAG_FOREGROUND;
+ }
if (isSplit) {
targetFlags |= InputTarget::FLAG_SPLIT;
@@ -2188,9 +2217,11 @@
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 &&
@@ -2268,10 +2299,17 @@
// Check permission to inject into all touched foreground windows and ensure there
// is at least one touched foreground window.
{
- bool haveForegroundWindow = false;
+ bool haveForegroundOrSpyWindow = false;
for (const TouchedWindow& touchedWindow : tempTouchState.windows) {
- if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {
- haveForegroundWindow = true;
+ const bool isForeground =
+ (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) != 0;
+ if (touchedWindow.windowHandle->getInfo()->isSpy()) {
+ haveForegroundOrSpyWindow = true;
+ LOG_ALWAYS_FATAL_IF(isForeground,
+ "Spy window cannot be dispatched as a foreground window.");
+ }
+ if (isForeground) {
+ haveForegroundOrSpyWindow = true;
if (!checkInjectionPermission(touchedWindow.windowHandle, entry.injectionState)) {
injectionResult = InputEventInjectionResult::PERMISSION_DENIED;
injectionPermission = INJECTION_PERMISSION_DENIED;
@@ -2280,8 +2318,8 @@
}
}
bool hasGestureMonitor = !tempTouchState.gestureMonitors.empty();
- if (!haveForegroundWindow && !hasGestureMonitor) {
- ALOGI("Dropping event because there is no touched foreground window in display "
+ if (!haveForegroundOrSpyWindow && !hasGestureMonitor) {
+ ALOGI("Dropping event because there is no touched window in display "
"%" PRId32 " or gesture monitor to receive it.",
displayId);
injectionResult = InputEventInjectionResult::FAILED;
@@ -2445,8 +2483,12 @@
}
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);
@@ -2479,8 +2521,12 @@
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 &&
@@ -3783,7 +3829,7 @@
originalMotionEntry.xCursorPosition,
originalMotionEntry.yCursorPosition,
originalMotionEntry.downTime, splitPointerCount,
- splitPointerProperties, splitPointerCoords, 0, 0);
+ splitPointerProperties, splitPointerCoords);
if (originalMotionEntry.injectionState) {
splitMotionEntry->injectionState = originalMotionEntry.injectionState;
@@ -4009,7 +4055,7 @@
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 &&
@@ -4239,10 +4285,8 @@
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;
@@ -4261,9 +4305,9 @@
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;
@@ -4427,35 +4471,28 @@
}
}
-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);
+ }
}
}
@@ -4653,15 +4690,27 @@
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.
@@ -5521,58 +5570,78 @@
status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) {
{ // acquire lock
std::scoped_lock _l(mLock);
- std::optional<int32_t> foundDisplayId = findGestureMonitorDisplayByTokenLocked(token);
- if (!foundDisplayId) {
- ALOGW("Attempted to pilfer pointers from an un-registered monitor or invalid token");
- return BAD_VALUE;
- }
- int32_t displayId = foundDisplayId.value();
-
- std::unordered_map<int32_t, TouchState>::iterator stateIt =
- mTouchStatesByDisplay.find(displayId);
- if (stateIt == mTouchStatesByDisplay.end()) {
- ALOGW("Failed to pilfer pointers: no pointers on display %" PRId32 ".", displayId);
- return BAD_VALUE;
- }
-
- TouchState& state = stateIt->second;
+ TouchState* statePtr = nullptr;
std::shared_ptr<InputChannel> requestingChannel;
- std::optional<int32_t> foundDeviceId;
- for (const auto& monitor : state.gestureMonitors) {
- if (monitor.inputChannel->getConnectionToken() == token) {
- requestingChannel = monitor.inputChannel;
- foundDeviceId = state.deviceId;
+ int32_t displayId;
+ int32_t deviceId;
+ const std::optional<int32_t> foundGestureMonitorDisplayId =
+ findGestureMonitorDisplayByTokenLocked(token);
+
+ // TODO: Optimize this function for pilfering from windows when removing gesture monitors.
+ if (foundGestureMonitorDisplayId) {
+ // A gesture monitor has requested to pilfer pointers.
+ displayId = *foundGestureMonitorDisplayId;
+ auto stateIt = mTouchStatesByDisplay.find(displayId);
+ if (stateIt == mTouchStatesByDisplay.end()) {
+ ALOGW("Failed to pilfer pointers: no pointers on display %" PRId32 ".", displayId);
+ return BAD_VALUE;
+ }
+ statePtr = &stateIt->second;
+
+ for (const auto& monitor : statePtr->gestureMonitors) {
+ if (monitor.inputChannel->getConnectionToken() == token) {
+ requestingChannel = monitor.inputChannel;
+ deviceId = statePtr->deviceId;
+ }
+ }
+ } else {
+ // Check if a window has requested to pilfer pointers.
+ for (auto& [curDisplayId, state] : mTouchStatesByDisplay) {
+ const sp<WindowInfoHandle>& windowHandle = state.getWindow(token);
+ if (windowHandle != nullptr) {
+ displayId = curDisplayId;
+ requestingChannel = getInputChannelLocked(token);
+ deviceId = state.deviceId;
+ statePtr = &state;
+ break;
+ }
}
}
- if (!foundDeviceId || !state.down) {
- ALOGW("Attempted to pilfer points from a monitor without any on-going pointer streams."
+
+ if (requestingChannel == nullptr) {
+ ALOGW("Attempted to pilfer pointers from an un-registered channel or invalid token");
+ return BAD_VALUE;
+ }
+ TouchState& state = *statePtr;
+ if (!state.down) {
+ ALOGW("Attempted to pilfer points from a channel without any on-going pointer streams."
" Ignoring.");
return BAD_VALUE;
}
- int32_t deviceId = foundDeviceId.value();
// Send cancel events to all the input channels we're stealing from.
CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
- "gesture monitor stole pointer stream");
+ "input channel stole pointer stream");
options.deviceId = deviceId;
options.displayId = displayId;
- std::string canceledWindows = "[";
+ std::string canceledWindows;
for (const TouchedWindow& window : state.windows) {
std::shared_ptr<InputChannel> channel =
getInputChannelLocked(window.windowHandle->getToken());
- if (channel != nullptr) {
+ if (channel != nullptr && channel->getConnectionToken() != token) {
synthesizeCancelationEventsForInputChannelLocked(channel, options);
- canceledWindows += channel->getName() + ", ";
+ canceledWindows += canceledWindows.empty() ? "[" : ", ";
+ canceledWindows += channel->getName();
}
}
- canceledWindows += "]";
- ALOGI("Monitor %s is stealing touch from %s", requestingChannel->getName().c_str(),
+ canceledWindows += canceledWindows.empty() ? "[]" : "]";
+ ALOGI("Channel %s is stealing touch from %s", requestingChannel->getName().c_str(),
canceledWindows.c_str());
// Then clear the current touch state so we stop dispatching to them as well.
state.split = false;
- state.filterNonMonitors();
+ state.filterWindowsExcept(token);
}
return OK;
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index e9591e4..ee50ec5 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -234,11 +234,12 @@
// 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, bool isStylus) const REQUIRES(mLock);
sp<Connection> getConnectionLocked(const sp<IBinder>& inputConnectionToken) const
REQUIRES(mLock);
@@ -282,7 +283,9 @@
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);
diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp
index 3bb0bc9..ad3c615 100644
--- a/services/inputflinger/dispatcher/InputState.cpp
+++ b/services/inputflinger/dispatcher/InputState.cpp
@@ -296,8 +296,7 @@
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 @@
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 759b3e7..08c7826 100644
--- a/services/inputflinger/dispatcher/TouchState.cpp
+++ b/services/inputflinger/dispatcher/TouchState.cpp
@@ -105,8 +105,9 @@
}
}
-void TouchState::filterNonMonitors() {
- windows.clear();
+void TouchState::filterWindowsExcept(const sp<IBinder>& token) {
+ std::erase_if(windows,
+ [&token](const TouchedWindow& w) { return w.windowHandle->getToken() != token; });
}
sp<WindowInfoHandle> TouchState::getFirstForegroundWindowHandle() const {
@@ -144,4 +145,14 @@
return nullptr;
}
+sp<WindowInfoHandle> TouchState::getWindow(const sp<IBinder>& token) const {
+ for (const TouchedWindow& touchedWindow : windows) {
+ const auto& windowHandle = touchedWindow.windowHandle;
+ if (windowHandle->getToken() == token) {
+ return windowHandle;
+ }
+ }
+ return nullptr;
+}
+
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h
index 762cc8a..83ca901 100644
--- a/services/inputflinger/dispatcher/TouchState.h
+++ b/services/inputflinger/dispatcher/TouchState.h
@@ -47,10 +47,11 @@
void addGestureMonitors(const std::vector<Monitor>& monitors);
void removeWindowByToken(const sp<IBinder>& token);
void filterNonAsIsTouchWindows();
- void filterNonMonitors();
+ void filterWindowsExcept(const sp<IBinder>& token);
sp<android::gui::WindowInfoHandle> getFirstForegroundWindowHandle() const;
bool isSlippery() const;
sp<android::gui::WindowInfoHandle> getWallpaperWindow() const;
+ sp<android::gui::WindowInfoHandle> getWindow(const sp<IBinder>&) const;
};
} // namespace inputdispatcher
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index d10f8b6..269bdab 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -2344,13 +2344,10 @@
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 7704a84..564db56 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -237,9 +237,7 @@
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 f1c0e5a..d83d74d 100644
--- a/services/inputflinger/reader/mapper/InputMapper.h
+++ b/services/inputflinger/reader/mapper/InputMapper.h
@@ -45,7 +45,7 @@
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 6bdb121..ad11b05 100644
--- a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
@@ -32,8 +32,7 @@
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 6f49f31..0a5de27 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -609,6 +609,270 @@
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 @@
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::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 9b020a6..9fd30e4 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -243,6 +243,7 @@
DIAMETER,
BOX,
AREA,
+ ftl_last = AREA
};
SizeCalibration sizeCalibration;
@@ -732,6 +733,10 @@
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 3c6f1ff..0814bc2 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -23,6 +23,7 @@
#include <gtest/gtest.h>
#include <input/Input.h>
#include <linux/input.h>
+#include <sys/epoll.h>
#include <cinttypes>
#include <thread>
@@ -953,6 +954,8 @@
sp<IBinder> getToken() { return mConsumer->getChannel()->getConnectionToken(); }
+ int getChannelFd() { return mConsumer->getChannel()->getFd().get(); }
+
protected:
std::unique_ptr<InputConsumer> mConsumer;
PreallocatedInputEventFactory mEventFactory;
@@ -1000,6 +1003,7 @@
mInfo.ownerPid = INJECTOR_PID;
mInfo.ownerUid = INJECTOR_UID;
mInfo.displayId = displayId;
+ mInfo.trustedOverlay = false;
}
sp<FakeWindowHandle> clone(
@@ -1041,6 +1045,8 @@
mInfo.transform = translate * displayTransform;
}
+ void setTouchableRegion(const Region& region) { mInfo.touchableRegion = region; }
+
void setType(WindowInfo::Type type) { mInfo.type = type; }
void setHasWallpaper(bool hasWallpaper) { mInfo.hasWallpaper = hasWallpaper; }
@@ -1049,7 +1055,9 @@
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);
@@ -1208,6 +1216,8 @@
void destroyReceiver() { mInputReceiver = nullptr; }
+ int getChannelFd() { return mInputReceiver->getChannelFd(); }
+
private:
const std::string mName;
std::unique_ptr<FakeInputReceiver> mInputReceiver;
@@ -1387,7 +1397,7 @@
static InputEventInjectionResult injectMotionEvent(
const std::unique_ptr<InputDispatcher>& dispatcher, int32_t action, int32_t source,
- int32_t displayId, const PointF& position,
+ int32_t displayId, const PointF& position = {100, 200},
const PointF& cursorPosition = {AMOTION_EVENT_INVALID_CURSOR_POSITION,
AMOTION_EVENT_INVALID_CURSOR_POSITION},
std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
@@ -2176,6 +2186,33 @@
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();
@@ -6280,4 +6317,399 @@
mSecondWindow->assertNoEvents();
}
+class InputDispatcherSpyWindowTest : public InputDispatcherTest {
+public:
+ sp<FakeWindowHandle> createSpy(const Flags<WindowInfo::Flag> flags) {
+ std::shared_ptr<FakeApplicationHandle> application =
+ std::make_shared<FakeApplicationHandle>();
+ std::string name = "Fake Spy ";
+ name += std::to_string(mSpyCount++);
+ 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;
+ }
+
+ sp<FakeWindowHandle> createForeground() {
+ std::shared_ptr<FakeApplicationHandle> application =
+ std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+ window->addFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
+ return window;
+ }
+
+private:
+ int mSpyCount{0};
+};
+
+/**
+ * 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) {
+ auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy}}});
+
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+}
+
+/**
+ * Verify the order in which different input windows receive events. The touched foreground window
+ * (if there is one) should always receive the event first. When there are multiple spy windows, the
+ * spy windows will receive the event according to their Z-order, where the top-most spy window will
+ * receive events before ones belows it.
+ *
+ * Here, we set up a scenario with four windows in the following Z order from the top:
+ * spy1, spy2, window, spy3.
+ * We then inject an event and verify that the foreground "window" receives it first, followed by
+ * "spy1" and "spy2". The "spy3" does not receive the event because it is underneath the foreground
+ * window.
+ */
+TEST_F(InputDispatcherSpyWindowTest, ReceivesInputInOrder) {
+ auto window = createForeground();
+ auto spy1 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ auto spy2 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ auto spy3 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy1, spy2, window, spy3}}});
+ const std::vector<sp<FakeWindowHandle>> channels{spy1, spy2, window, spy3};
+ const size_t numChannels = channels.size();
+
+ base::unique_fd epollFd(epoll_create1(0 /*flags*/));
+ if (!epollFd.ok()) {
+ FAIL() << "Failed to create epoll fd";
+ }
+
+ for (size_t i = 0; i < numChannels; i++) {
+ struct epoll_event event = {.events = EPOLLIN, .data.u64 = i};
+ if (epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, channels[i]->getChannelFd(), &event) < 0) {
+ FAIL() << "Failed to add fd to epoll";
+ }
+ }
+
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+ std::vector<size_t> eventOrder;
+ std::vector<struct epoll_event> events(numChannels);
+ for (;;) {
+ const int nFds = epoll_wait(epollFd.get(), events.data(), static_cast<int>(numChannels),
+ (100ms).count());
+ if (nFds < 0) {
+ FAIL() << "Failed to call epoll_wait";
+ }
+ if (nFds == 0) {
+ break; // epoll_wait timed out
+ }
+ for (int i = 0; i < nFds; i++) {
+ ASSERT_EQ(EPOLLIN, events[i].events);
+ eventOrder.push_back(events[i].data.u64);
+ channels[i]->consumeMotionDown();
+ }
+ }
+
+ // Verify the order in which the events were received.
+ EXPECT_EQ(3u, eventOrder.size());
+ EXPECT_EQ(2u, eventOrder[0]); // index 2: window
+ EXPECT_EQ(0u, eventOrder[1]); // index 0: spy1
+ EXPECT_EQ(1u, eventOrder[2]); // index 1: spy2
+}
+
+/**
+ * A spy window using the NOT_TOUCHABLE flag does not receive events.
+ */
+TEST_F(InputDispatcherSpyWindowTest, NotTouchable) {
+ auto window = createForeground();
+ auto spy = createSpy(WindowInfo::Flag::NOT_TOUCHABLE);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
+
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ spy->assertNoEvents();
+}
+
+/**
+ * A spy window will only receive gestures that originate within its touchable region. Gestures that
+ * have their ACTION_DOWN outside of the touchable region of the spy window will not be dispatched
+ * to the window.
+ */
+TEST_F(InputDispatcherSpyWindowTest, TouchableRegion) {
+ auto window = createForeground();
+ auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ spy->setTouchableRegion(Region{{0, 0, 20, 20}});
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
+
+ // Inject an event outside the spy window's touchable region.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ window->consumeMotionDown();
+ spy->assertNoEvents();
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ window->consumeMotionUp();
+ spy->assertNoEvents();
+
+ // Inject an event inside the spy window's touchable region.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {5, 10}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ window->consumeMotionDown();
+ spy->consumeMotionDown();
+}
+
+/**
+ * A spy window that is a modal window will receive gestures outside of its frame and touchable
+ * region.
+ */
+TEST_F(InputDispatcherSpyWindowTest, ModalWindow) {
+ auto window = createForeground();
+ auto spy = createSpy(static_cast<WindowInfo::Flag>(0));
+ // This spy window does not have the NOT_TOUCH_MODAL flag set.
+ spy->setFrame(Rect{0, 0, 20, 20});
+ 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";
+ window->consumeMotionDown();
+ spy->consumeMotionDown();
+}
+
+/**
+ * A spy window can listen for touches outside its touchable region using the WATCH_OUTSIDE_TOUCHES
+ * flag.
+ */
+TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) {
+ auto window = createForeground();
+ auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::WATCH_OUTSIDE_TOUCH);
+ spy->setFrame(Rect{0, 0, 20, 20});
+ 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";
+ window->consumeMotionDown();
+ spy->consumeMotionOutside();
+}
+
+/**
+ * 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.
+ */
+TEST_F(InputDispatcherSpyWindowTest, PilferPointers) {
+ auto window = createForeground();
+ auto spy1 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ auto spy2 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy1, spy2, window}}});
+
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ window->consumeMotionDown();
+ spy1->consumeMotionDown();
+ spy2->consumeMotionDown();
+
+ // Pilfer pointers from the second spy window.
+ mDispatcher->pilferPointers(spy2->getToken());
+ spy2->assertNoEvents();
+ spy1->consumeMotionCancel();
+ window->consumeMotionCancel();
+
+ // The rest of the gesture should only be sent to the second spy window.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ spy2->consumeMotionMove();
+ spy1->assertNoEvents();
+ window->assertNoEvents();
+}
+
+/**
+ * Even when a spy window spans over multiple foreground windows, the spy should receive all
+ * pointers that are down within its bounds.
+ */
+TEST_F(InputDispatcherSpyWindowTest, ReceivesMultiplePointers) {
+ auto windowLeft = createForeground();
+ windowLeft->setFrame({0, 0, 100, 200});
+ auto windowRight = createForeground();
+ windowRight->setFrame({100, 0, 200, 200});
+ auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ spy->setFrame({0, 0, 200, 200});
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, windowLeft, windowRight}}});
+
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {50, 50}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ windowLeft->consumeMotionDown();
+ spy->consumeMotionDown();
+
+ const MotionEvent secondFingerDownEvent =
+ MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN |
+ (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ AINPUT_SOURCE_TOUCHSCREEN)
+ .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+ .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
+ .pointer(
+ PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(50))
+ .build();
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
+ InputEventInjectionSync::WAIT_FOR_RESULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ windowRight->consumeMotionDown();
+ spy->consumeMotionPointerDown(1 /*pointerIndex*/);
+}
+
+/**
+ * When the first pointer lands outside the spy window and the second pointer lands inside it, the
+ * the spy should receive the second pointer with ACTION_DOWN.
+ */
+TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) {
+ auto window = createForeground();
+ window->setFrame({0, 0, 200, 200});
+ auto spyRight = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ spyRight->setFrame({100, 0, 200, 200});
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyRight, window}}});
+
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {50, 50}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ window->consumeMotionDown();
+ spyRight->assertNoEvents();
+
+ const MotionEvent secondFingerDownEvent =
+ MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN |
+ (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ AINPUT_SOURCE_TOUCHSCREEN)
+ .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+ .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
+ .pointer(
+ PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(50))
+ .build();
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
+ InputEventInjectionSync::WAIT_FOR_RESULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ window->consumeMotionPointerDown(1 /*pointerIndex*/);
+ 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 336afc6..068e03c 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -78,6 +78,15 @@
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 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 {
@@ -2344,8 +2371,7 @@
mDevice->sendTrackingId(SECOND_TRACKING_ID);
mDevice->sendDown(secondPoint + Point(1, 1));
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);
@@ -2355,8 +2381,7 @@
// ACTION_POINTER_UP (Second slot)
mDevice->sendPointerUp();
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);
@@ -2382,8 +2407,7 @@
mDevice->sendTrackingId(SECOND_TRACKING_ID);
mDevice->sendDown(secondPoint);
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));
@@ -2395,8 +2419,7 @@
// Expect to receive the ACTION_POINTER_UP with cancel flag.
mDevice->sendToolType(MT_TOOL_PALM);
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.
@@ -6488,7 +6511,7 @@
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 +6645,7 @@
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 +6705,7 @@
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 +6780,7 @@
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 +6809,7 @@
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 +6874,57 @@
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 +6955,7 @@
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 +6996,7 @@
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 +7041,7 @@
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 +7060,7 @@
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 +7125,7 @@
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 +7165,7 @@
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 +7206,7 @@
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 +7226,7 @@
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 +7391,7 @@
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 +8521,7 @@
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 +8531,7 @@
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 +8596,7 @@
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 +8606,7 @@
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 +8694,7 @@
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 +8703,7 @@
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 +8777,7 @@
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 +8786,7 @@
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 +8898,7 @@
// 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/sensorservice/Android.bp b/services/sensorservice/Android.bp
index 6a1c9e4..d5b629d 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -86,10 +86,7 @@
"libpermission",
],
- pgo: {
- sampling: true,
- profile_file: "sensorservice/libsensorservice.profdata",
- },
+ afdo: true,
}
cc_binary {
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 1e3a47b..a0e30ac 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -613,6 +613,7 @@
}
status_t SensorDevice::flush(void* /*ident*/, int handle) {
+ if (mHalWrapper == nullptr) return NO_INIT;
return mHalWrapper->flush(handle);
}
@@ -752,6 +753,7 @@
}
status_t SensorDevice::injectSensorData(const sensors_event_t* injected_sensor_event) {
+ if (mHalWrapper == nullptr) return NO_INIT;
return mHalWrapper->injectSensorData(injected_sensor_event);
}
@@ -761,6 +763,7 @@
}
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);
@@ -772,6 +775,7 @@
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/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 5543ad5..08dd22d 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -39,6 +39,8 @@
#include "DisplayHardware/PowerAdvisor.h"
+using aidl::android::hardware::graphics::composer3::DisplayCapability;
+
namespace android::compositionengine::impl {
std::shared_ptr<Display> createDisplay(
@@ -252,7 +254,7 @@
const auto& hwc = getCompositionEngine().getHwComposer();
if (const auto halDisplayId = HalDisplayId::tryCast(mId)) {
return hwc.hasDisplayCapability(*halDisplayId,
- hal::DisplayCapability::SKIP_CLIENT_COLOR_TRANSFORM);
+ DisplayCapability::SKIP_CLIENT_COLOR_TRANSFORM);
}
return hwc.hasCapability(hal::Capability::SKIP_CLIENT_COLOR_TRANSFORM);
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 88f00a5..8558a80 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -634,6 +634,7 @@
*/
using DisplayGetSkipColorTransformTest = DisplayWithLayersTestCommon;
+using aidl::android::hardware::graphics::composer3::DisplayCapability;
TEST_F(DisplayGetSkipColorTransformTest, checksCapabilityIfGpuDisplay) {
EXPECT_CALL(mHwComposer, hasCapability(hal::Capability::SKIP_CLIENT_COLOR_TRANSFORM))
@@ -646,7 +647,7 @@
TEST_F(DisplayGetSkipColorTransformTest, checksDisplayCapability) {
EXPECT_CALL(mHwComposer,
hasDisplayCapability(HalDisplayId(DEFAULT_DISPLAY_ID),
- hal::DisplayCapability::SKIP_CLIENT_COLOR_TRANSFORM))
+ DisplayCapability::SKIP_CLIENT_COLOR_TRANSFORM))
.WillOnce(Return(true));
EXPECT_TRUE(mDisplay->getSkipColorTransform());
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 0f174db..a590e2a 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -43,7 +43,9 @@
MOCK_CONST_METHOD3(getDisplayIdentificationData,
bool(hal::HWDisplayId, uint8_t*, DisplayIdentificationData*));
MOCK_CONST_METHOD1(hasCapability, bool(hal::Capability));
- MOCK_CONST_METHOD2(hasDisplayCapability, bool(HalDisplayId, hal::DisplayCapability));
+ MOCK_CONST_METHOD2(hasDisplayCapability,
+ bool(HalDisplayId,
+ aidl::android::hardware::graphics::composer3::DisplayCapability));
MOCK_CONST_METHOD0(getMaxVirtualDisplayCount, size_t());
MOCK_CONST_METHOD0(getMaxVirtualDisplayDimension, size_t());
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index 081f526..1091a75 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -373,10 +373,14 @@
Error AidlComposer::getChangedCompositionTypes(
Display display, std::vector<Layer>* outLayers,
std::vector<aidl::android::hardware::graphics::composer3::Composition>* outTypes) {
- std::vector<int64_t> layers;
- mReader.takeChangedCompositionTypes(translate<int64_t>(display), &layers, outTypes);
+ const auto changedLayers = mReader.takeChangedCompositionTypes(translate<int64_t>(display));
+ outLayers->reserve(changedLayers.size());
+ outTypes->reserve(changedLayers.size());
- *outLayers = translate<Layer>(layers);
+ for (const auto& layer : changedLayers) {
+ outLayers->emplace_back(translate<Layer>(layer.layer));
+ outTypes->emplace_back(layer.composition);
+ }
return Error::NONE;
}
@@ -429,10 +433,15 @@
Error AidlComposer::getDisplayRequests(Display display, uint32_t* outDisplayRequestMask,
std::vector<Layer>* outLayers,
std::vector<uint32_t>* outLayerRequestMasks) {
- std::vector<int64_t> layers;
- mReader.takeDisplayRequests(translate<int64_t>(display), outDisplayRequestMask, &layers,
- outLayerRequestMasks);
- *outLayers = translate<Layer>(layers);
+ const auto displayRequests = mReader.takeDisplayRequests(translate<int64_t>(display));
+ *outDisplayRequestMask = translate<uint32_t>(displayRequests.mask);
+ outLayers->reserve(displayRequests.layerRequests.size());
+ outLayerRequestMasks->reserve(displayRequests.layerRequests.size());
+
+ for (const auto& layer : displayRequests.layerRequests) {
+ outLayers->emplace_back(translate<Layer>(layer.layer));
+ outLayerRequestMasks->emplace_back(translate<uint32_t>(layer.mask));
+ }
return Error::NONE;
}
@@ -469,9 +478,17 @@
Error AidlComposer::getReleaseFences(Display display, std::vector<Layer>* outLayers,
std::vector<int>* outReleaseFences) {
- std::vector<int64_t> layers;
- mReader.takeReleaseFences(translate<int64_t>(display), &layers, outReleaseFences);
- *outLayers = translate<Layer>(layers);
+ auto fences = mReader.takeReleaseFences(translate<int64_t>(display));
+ outLayers->reserve(fences.size());
+ outReleaseFences->reserve(fences.size());
+
+ for (auto& fence : fences) {
+ outLayers->emplace_back(translate<Layer>(fence.layer));
+ // take ownership
+ const int fenceOwner = fence.fence.get();
+ *fence.fence.getR() = -1;
+ outReleaseFences->emplace_back(fenceOwner);
+ }
return Error::NONE;
}
@@ -484,8 +501,10 @@
return error;
}
- mReader.takePresentFence(translate<int64_t>(display), outPresentFence);
-
+ auto fence = mReader.takePresentFence(translate<int64_t>(display));
+ // take ownership
+ *outPresentFence = fence.get();
+ *fence.getR() = -1;
return Error::NONE;
}
@@ -597,13 +616,22 @@
return error;
}
- mReader.takePresentOrValidateStage(translate<int64_t>(display), state);
-
- if (*state == 1) { // Present succeeded
- mReader.takePresentFence(translate<int64_t>(display), outPresentFence);
+ const auto result = mReader.takePresentOrValidateStage(translate<int64_t>(display));
+ if (!result.has_value()) {
+ *state = translate<uint32_t>(-1);
+ return Error::NO_RESOURCES;
}
- if (*state == 0) { // Validate succeeded.
+ *state = translate<uint32_t>(*result);
+
+ if (*result == PresentOrValidate::Result::Presented) {
+ auto fence = mReader.takePresentFence(translate<int64_t>(display));
+ // take ownership
+ *outPresentFence = fence.get();
+ *fence.getR() = -1;
+ }
+
+ if (*result == PresentOrValidate::Result::Validated) {
mReader.hasChanges(translate<int64_t>(display), outNumTypes, outNumRequests);
}
@@ -711,14 +739,16 @@
return Error::NONE;
}
- std::vector<CommandResultPayload> results;
- auto status = mAidlComposerClient->executeCommands(commands, &results);
- if (!status.isOk()) {
- ALOGE("executeCommands failed %s", status.getDescription().c_str());
- return static_cast<Error>(status.getServiceSpecificError());
- }
+ { // scope for results
+ std::vector<CommandResultPayload> results;
+ auto status = mAidlComposerClient->executeCommands(commands, &results);
+ if (!status.isOk()) {
+ ALOGE("executeCommands failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
- mReader.parse(results);
+ mReader.parse(std::move(results));
+ }
const auto commandErrors = mReader.takeErrors();
Error error = Error::NONE;
for (const auto& cmdErr : commandErrors) {
@@ -887,15 +917,14 @@
}
Error AidlComposer::getDisplayCapabilities(Display display,
- std::vector<DisplayCapability>* outCapabilities) {
- std::vector<AidlDisplayCapability> capabilities;
- const auto status =
- mAidlComposerClient->getDisplayCapabilities(translate<int64_t>(display), &capabilities);
+ std::vector<AidlDisplayCapability>* outCapabilities) {
+ const auto status = mAidlComposerClient->getDisplayCapabilities(translate<int64_t>(display),
+ outCapabilities);
if (!status.isOk()) {
ALOGE("getDisplayCapabilities failed %s", status.getDescription().c_str());
+ outCapabilities->clear();
return static_cast<Error>(status.getServiceSpecificError());
}
- *outCapabilities = translate<DisplayCapability>(capabilities);
return Error::NONE;
}
@@ -993,9 +1022,10 @@
Error AidlComposer::getClientTargetProperty(
Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty,
float* whitePointNits) {
- ClientTargetProperty property;
- mReader.takeClientTargetProperty(translate<int64_t>(display), &property, whitePointNits);
- *outClientTargetProperty = translate<IComposerClient::ClientTargetProperty>(property);
+ const auto property = mReader.takeClientTargetProperty(translate<int64_t>(display));
+ *outClientTargetProperty =
+ translate<IComposerClient::ClientTargetProperty>(property.clientTargetProperty);
+ *whitePointNits = property.whitePointNits;
return Error::NONE;
}
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
index 777b295..5c41982 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
@@ -38,6 +38,7 @@
#include <android/hardware/graphics/composer3/ComposerClientWriter.h>
#include <aidl/android/hardware/graphics/composer3/Composition.h>
+#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
@@ -182,8 +183,10 @@
Error setDisplayBrightness(Display display, float brightness) override;
// Composer HAL 2.4
- Error getDisplayCapabilities(Display display,
- std::vector<DisplayCapability>* outCapabilities) override;
+ Error getDisplayCapabilities(
+ Display display,
+ std::vector<aidl::android::hardware::graphics::composer3::DisplayCapability>*
+ outCapabilities) override;
V2_4::Error getDisplayConnectionType(Display display,
IComposerClient::DisplayConnectionType* outType) override;
V2_4::Error getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriod) override;
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index a6a1e6f..f491a00 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -32,6 +32,7 @@
#include <utils/StrongPointer.h>
#include <aidl/android/hardware/graphics/composer3/Composition.h>
+#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
@@ -64,7 +65,6 @@
using V2_4::IComposerClient;
using V2_4::VsyncPeriodChangeTimeline;
using V2_4::VsyncPeriodNanos;
-using DisplayCapability = IComposerClient::DisplayCapability;
using PerFrameMetadata = IComposerClient::PerFrameMetadata;
using PerFrameMetadataKey = IComposerClient::PerFrameMetadataKey;
using PerFrameMetadataBlob = IComposerClient::PerFrameMetadataBlob;
@@ -207,8 +207,10 @@
virtual Error setDisplayBrightness(Display display, float brightness) = 0;
// Composer HAL 2.4
- virtual Error getDisplayCapabilities(Display display,
- std::vector<DisplayCapability>* outCapabilities) = 0;
+ virtual Error getDisplayCapabilities(
+ Display display,
+ std::vector<aidl::android::hardware::graphics::composer3::DisplayCapability>*
+ outCapabilities) = 0;
virtual V2_4::Error getDisplayConnectionType(
Display display, IComposerClient::DisplayConnectionType* outType) = 0;
virtual V2_4::Error getDisplayVsyncPeriod(Display display,
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 3dcea61..548d839 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -40,6 +40,7 @@
#include "ComposerHal.h"
using aidl::android::hardware::graphics::composer3::Composition;
+using aidl::android::hardware::graphics::composer3::DisplayCapability;
namespace android {
@@ -285,15 +286,15 @@
return Error::NONE;
}
-bool Display::hasCapability(hal::DisplayCapability capability) const {
+bool Display::hasCapability(DisplayCapability capability) const {
std::scoped_lock lock(mDisplayCapabilitiesMutex);
if (mDisplayCapabilities) {
return mDisplayCapabilities->count(capability) > 0;
}
- ALOGW("Can't query capability %d."
+ ALOGW("Can't query capability %s."
" Display Capabilities were not queried from HWC yet",
- static_cast<int>(capability));
+ to_string(capability).c_str());
return false;
}
@@ -458,14 +459,14 @@
if (mode == PowerMode::ON) {
std::call_once(mDisplayCapabilityQueryFlag, [this]() {
- std::vector<Hwc2::DisplayCapability> tmpCapabilities;
+ std::vector<DisplayCapability> tmpCapabilities;
auto error =
static_cast<Error>(mComposer.getDisplayCapabilities(mId, &tmpCapabilities));
if (error == Error::NONE) {
std::scoped_lock lock(mDisplayCapabilitiesMutex);
mDisplayCapabilities.emplace();
for (auto capability : tmpCapabilities) {
- mDisplayCapabilities->emplace(static_cast<DisplayCapability>(capability));
+ mDisplayCapabilities->emplace(capability);
}
} else if (error == Error::UNSUPPORTED) {
std::scoped_lock lock(mDisplayCapabilitiesMutex);
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index c2ebd45..731d7f6 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -37,6 +37,7 @@
#include "Hal.h"
#include <aidl/android/hardware/graphics/composer3/Composition.h>
+#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
namespace android {
@@ -82,7 +83,8 @@
virtual hal::HWDisplayId getId() const = 0;
virtual bool isConnected() const = 0;
virtual void setConnected(bool connected) = 0; // For use by Device only
- virtual bool hasCapability(hal::DisplayCapability) const = 0;
+ virtual bool hasCapability(
+ aidl::android::hardware::graphics::composer3::DisplayCapability) const = 0;
virtual bool isVsyncPeriodSwitchSupported() const = 0;
virtual void onLayerDestroyed(hal::HWLayerId layerId) = 0;
@@ -224,7 +226,8 @@
hal::HWDisplayId getId() const override { return mId; }
bool isConnected() const override { return mIsConnected; }
void setConnected(bool connected) override; // For use by Device only
- bool hasCapability(hal::DisplayCapability) const override EXCLUDES(mDisplayCapabilitiesMutex);
+ bool hasCapability(aidl::android::hardware::graphics::composer3::DisplayCapability)
+ const override EXCLUDES(mDisplayCapabilitiesMutex);
bool isVsyncPeriodSwitchSupported() const override;
void onLayerDestroyed(hal::HWLayerId layerId) override;
@@ -253,8 +256,9 @@
mutable std::mutex mDisplayCapabilitiesMutex;
std::once_flag mDisplayCapabilityQueryFlag;
- std::optional<std::unordered_set<hal::DisplayCapability>> mDisplayCapabilities
- GUARDED_BY(mDisplayCapabilitiesMutex);
+ std::optional<
+ std::unordered_set<aidl::android::hardware::graphics::composer3::DisplayCapability>>
+ mDisplayCapabilities GUARDED_BY(mDisplayCapabilitiesMutex);
};
} // namespace impl
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 3b4fff0..546e677 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -182,8 +182,9 @@
return mCapabilities.count(capability) > 0;
}
-bool HWComposer::hasDisplayCapability(HalDisplayId displayId,
- hal::DisplayCapability capability) const {
+bool HWComposer::hasDisplayCapability(
+ HalDisplayId displayId,
+ aidl::android::hardware::graphics::composer3::DisplayCapability capability) const {
RETURN_IF_INVALID_DISPLAY(displayId, false);
return mDisplayData.at(displayId).hwcDisplay->hasCapability(capability);
}
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index b7f1064..69adfcd 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -44,6 +44,7 @@
#include "Hal.h"
#include <aidl/android/hardware/graphics/composer3/Composition.h>
+#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
namespace android {
@@ -110,7 +111,9 @@
DisplayIdentificationData* outData) const = 0;
virtual bool hasCapability(hal::Capability) const = 0;
- virtual bool hasDisplayCapability(HalDisplayId, hal::DisplayCapability) const = 0;
+ virtual bool hasDisplayCapability(
+ HalDisplayId,
+ aidl::android::hardware::graphics::composer3::DisplayCapability) const = 0;
virtual size_t getMaxVirtualDisplayCount() const = 0;
virtual size_t getMaxVirtualDisplayDimension() const = 0;
@@ -267,7 +270,9 @@
DisplayIdentificationData* outData) const override;
bool hasCapability(hal::Capability) const override;
- bool hasDisplayCapability(HalDisplayId, hal::DisplayCapability) const override;
+ bool hasDisplayCapability(
+ HalDisplayId,
+ aidl::android::hardware::graphics::composer3::DisplayCapability) const override;
size_t getMaxVirtualDisplayCount() const override;
size_t getMaxVirtualDisplayDimension() const override;
diff --git a/services/surfaceflinger/DisplayHardware/Hal.h b/services/surfaceflinger/DisplayHardware/Hal.h
index 7236868..e33dc0f 100644
--- a/services/surfaceflinger/DisplayHardware/Hal.h
+++ b/services/surfaceflinger/DisplayHardware/Hal.h
@@ -21,6 +21,7 @@
#include <android/hardware/graphics/composer/2.4/IComposerClient.h>
#include <aidl/android/hardware/graphics/composer3/Composition.h>
+#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
#define ERROR_HAS_CHANGES 5
@@ -55,7 +56,6 @@
using ContentType = IComposerClient::ContentType;
using Capability = IComposer::Capability;
using ClientTargetProperty = IComposerClient::ClientTargetProperty;
-using DisplayCapability = IComposerClient::DisplayCapability;
using DisplayRequest = IComposerClient::DisplayRequest;
using DisplayType = IComposerClient::DisplayType;
using HWConfigId = V2_1::Config;
@@ -118,6 +118,29 @@
}
}
+inline std::string to_string(
+ aidl::android::hardware::graphics::composer3::DisplayCapability displayCapability) {
+ switch (displayCapability) {
+ case aidl::android::hardware::graphics::composer3::DisplayCapability::INVALID:
+ return "Invalid";
+ case aidl::android::hardware::graphics::composer3::DisplayCapability::
+ SKIP_CLIENT_COLOR_TRANSFORM:
+ return "SkipColorTransform";
+ case aidl::android::hardware::graphics::composer3::DisplayCapability::DOZE:
+ return "Doze";
+ case aidl::android::hardware::graphics::composer3::DisplayCapability::BRIGHTNESS:
+ return "Brightness";
+ case aidl::android::hardware::graphics::composer3::DisplayCapability::PROTECTED_CONTENTS:
+ return "ProtectedContents";
+ case aidl::android::hardware::graphics::composer3::DisplayCapability::AUTO_LOW_LATENCY_MODE:
+ return "AutoLowLatencyMode";
+ case aidl::android::hardware::graphics::composer3::DisplayCapability::SUSPEND:
+ return "Suspend";
+ default:
+ return "Unknown";
+ }
+}
+
inline std::string to_string(hardware::graphics::composer::hal::V2_4::Error error) {
// 5 is reserved for historical reason, during validation 5 means has changes.
if (ERROR_HAS_CHANGES == static_cast<int32_t>(error)) {
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index 96f4496..7946002 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -35,6 +35,8 @@
#include <algorithm>
#include <cinttypes>
+using aidl::android::hardware::graphics::composer3::DisplayCapability;
+
namespace android {
using hardware::hidl_handle;
@@ -1020,6 +1022,15 @@
// Composer HAL 2.4
+namespace {
+template <typename T>
+void copyCapabilities(const T& tmpCaps, std::vector<DisplayCapability>* outCapabilities) {
+ outCapabilities->resize(tmpCaps.size());
+ std::transform(tmpCaps.begin(), tmpCaps.end(), outCapabilities->begin(),
+ [](auto cap) { return static_cast<DisplayCapability>(cap); });
+}
+} // anonymous namespace
+
Error HidlComposer::getDisplayCapabilities(Display display,
std::vector<DisplayCapability>* outCapabilities) {
if (!mClient_2_3) {
@@ -1034,7 +1045,7 @@
if (error != V2_4::Error::NONE) {
return;
}
- *outCapabilities = tmpCaps;
+ copyCapabilities(tmpCaps, outCapabilities);
});
} else {
mClient_2_3
@@ -1044,9 +1055,7 @@
return;
}
- outCapabilities->resize(tmpCaps.size());
- std::transform(tmpCaps.begin(), tmpCaps.end(), outCapabilities->begin(),
- [](auto cap) { return static_cast<DisplayCapability>(cap); });
+ copyCapabilities(tmpCaps, outCapabilities);
});
}
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
index 8190c17..3b62fe0 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
@@ -70,7 +70,6 @@
using V2_4::IComposerClient;
using V2_4::VsyncPeriodChangeTimeline;
using V2_4::VsyncPeriodNanos;
-using DisplayCapability = IComposerClient::DisplayCapability;
using PerFrameMetadata = IComposerClient::PerFrameMetadata;
using PerFrameMetadataKey = IComposerClient::PerFrameMetadataKey;
using PerFrameMetadataBlob = IComposerClient::PerFrameMetadataBlob;
@@ -293,8 +292,10 @@
Error setDisplayBrightness(Display display, float brightness) override;
// Composer HAL 2.4
- Error getDisplayCapabilities(Display display,
- std::vector<DisplayCapability>* outCapabilities) override;
+ Error getDisplayCapabilities(
+ Display display,
+ std::vector<aidl::android::hardware::graphics::composer3::DisplayCapability>*
+ outCapabilities) override;
V2_4::Error getDisplayConnectionType(Display display,
IComposerClient::DisplayConnectionType* outType) override;
V2_4::Error getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriod) override;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 4d7e4d9..a6eeda2 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -140,6 +140,8 @@
#include "android-base/stringprintf.h"
#include "android-base/strings.h"
+#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
+
#define MAIN_THREAD ACQUIRE(mStateLock) RELEASE(mStateLock)
#define ON_MAIN_THREAD(expr) \
@@ -160,6 +162,8 @@
#define NO_THREAD_SAFETY_ANALYSIS \
_Pragma("GCC error \"Prefer MAIN_THREAD macros or {Conditional,Timed,Unnecessary}Lock.\"")
+using aidl::android::hardware::graphics::composer3::DisplayCapability;
+
namespace android {
using namespace std::string_literals;
@@ -364,7 +368,8 @@
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
const int uid = ipc->getCallingUid();
- return PermissionCache::checkPermission(sInternalSystemWindow, pid, uid);
+ return uid == AID_GRAPHICS || uid == AID_SYSTEM ||
+ PermissionCache::checkPermission(sInternalSystemWindow, pid, uid);
}
SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag)
@@ -1095,7 +1100,7 @@
info->autoLowLatencyModeSupported =
getHwComposer().hasDisplayCapability(*displayId,
- hal::DisplayCapability::AUTO_LOW_LATENCY_MODE);
+ DisplayCapability::AUTO_LOW_LATENCY_MODE);
std::vector<hal::ContentType> types;
getHwComposer().getSupportedContentTypes(*displayId, &types);
info->gameContentTypeSupported = std::any_of(types.begin(), types.end(), [](auto type) {
@@ -1660,8 +1665,7 @@
if (!displayId) {
return NAME_NOT_FOUND;
}
- *outSupport =
- getHwComposer().hasDisplayCapability(*displayId, hal::DisplayCapability::BRIGHTNESS);
+ *outSupport = getHwComposer().hasDisplayCapability(*displayId, DisplayCapability::BRIGHTNESS);
return NO_ERROR;
}
@@ -3099,41 +3103,61 @@
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/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 89a517f..f1e9b31 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -324,7 +324,9 @@
template <typename Case>
static void setupPreconditionCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mComposer, getDisplayCapabilities(HWC_DISPLAY, _))
- .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hwc2::DisplayCapability>({})),
+ .WillOnce(DoAll(SetArgPointee<1>(
+ std::vector<aidl::android::hardware::graphics::composer3::
+ DisplayCapability>({})),
Return(Error::NONE)));
}
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index 0a3437a..69ac26e 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -66,9 +66,9 @@
using testing::Return;
using testing::SetArgPointee;
+using aidl::android::hardware::graphics::composer3::DisplayCapability;
using hal::ColorMode;
using hal::Connection;
-using hal::DisplayCapability;
using hal::DisplayType;
using hal::Error;
using hal::Hdr;
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index a1aacc0..8c51313 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -121,7 +121,10 @@
MOCK_METHOD3(setLayerPerFrameMetadataBlobs,
Error(Display, Layer, const std::vector<IComposerClient::PerFrameMetadataBlob>&));
MOCK_METHOD2(setDisplayBrightness, Error(Display, float));
- MOCK_METHOD2(getDisplayCapabilities, Error(Display, std::vector<DisplayCapability>*));
+ MOCK_METHOD2(
+ getDisplayCapabilities,
+ Error(Display,
+ std::vector<aidl::android::hardware::graphics::composer3::DisplayCapability>*));
MOCK_METHOD2(getDisplayConnectionType,
V2_4::Error(Display, IComposerClient::DisplayConnectionType*));
MOCK_METHOD3(getSupportedDisplayVsyncPeriods,
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
index b43bc0e..821fc8f 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
@@ -30,7 +30,9 @@
MOCK_METHOD(hal::HWDisplayId, getId, (), (const, override));
MOCK_METHOD(bool, isConnected, (), (const, override));
MOCK_METHOD(void, setConnected, (bool), (override));
- MOCK_METHOD(bool, hasCapability, (hal::DisplayCapability), (const, override));
+ MOCK_METHOD(bool, hasCapability,
+ (aidl::android::hardware::graphics::composer3::DisplayCapability),
+ (const, override));
MOCK_METHOD(bool, isVsyncPeriodSwitchSupported, (), (const, override));
MOCK_METHOD(void, onLayerDestroyed, (hal::HWLayerId), (override));