Merge "Kawase blur feedback"
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index be7e3e1..acca11a 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -76,6 +76,7 @@
defaults: ["dumpstate_cflag_defaults"],
shared_libs: [
"android.hardware.dumpstate@1.0",
+ "android.hardware.dumpstate@1.1",
"libziparchive",
"libbase",
"libbinder",
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 8e0f8a3..3a79357 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -64,6 +64,8 @@
#include <android-base/unique_fd.h>
#include <android/content/pm/IPackageManagerNative.h>
#include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
+#include <android/hardware/dumpstate/1.1/IDumpstateDevice.h>
+#include <android/hardware/dumpstate/1.1/types.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <android/os/IIncidentCompanion.h>
#include <binder/IServiceManager.h>
@@ -85,7 +87,11 @@
#include "DumpstateService.h"
#include "dumpstate.h"
-using ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
+using IDumpstateDevice_1_0 = ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
+using IDumpstateDevice_1_1 = ::android::hardware::dumpstate::V1_1::IDumpstateDevice;
+using ::android::hardware::dumpstate::V1_1::DumpstateMode;
+using ::android::hardware::dumpstate::V1_1::DumpstateStatus;
+using ::android::hardware::dumpstate::V1_1::toString;
using ::std::literals::chrono_literals::operator""ms;
using ::std::literals::chrono_literals::operator""s;
@@ -1892,8 +1898,8 @@
std::bind([](std::string path) { android::os::UnlinkAndLogOnError(path); }, paths[i])));
}
- sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService());
- if (dumpstate_device == nullptr) {
+ sp<IDumpstateDevice_1_0> dumpstate_device_1_0(IDumpstateDevice_1_0::getService());
+ if (dumpstate_device_1_0 == nullptr) {
MYLOGE("No IDumpstateDevice implementation\n");
return;
}
@@ -1924,29 +1930,54 @@
handle.get()->data[i] = fd.release();
}
- // Given that bugreport is required to diagnose failures, it's better to
- // set an arbitrary amount of timeout for IDumpstateDevice than to block the
- // rest of bugreport. In the timeout case, we will kill dumpstate board HAL
- // and grab whatever dumped
- std::packaged_task<bool()>
- dumpstate_task([paths, dumpstate_device, &handle]() -> bool {
- android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle.get());
+ // Given that bugreport is required to diagnose failures, it's better to set an arbitrary amount
+ // of timeout for IDumpstateDevice than to block the rest of bugreport. In the timeout case, we
+ // will kill the HAL and grab whatever it dumped in time.
+ constexpr size_t timeout_sec = 30;
+ // Prefer version 1.1 if available. New devices launching with R are no longer allowed to
+ // implement just 1.0.
+ const char* descriptor_to_kill;
+ using DumpstateBoardTask = std::packaged_task<bool()>;
+ DumpstateBoardTask dumpstate_board_task;
+ sp<IDumpstateDevice_1_1> dumpstate_device_1_1(
+ IDumpstateDevice_1_1::castFrom(dumpstate_device_1_0));
+ if (dumpstate_device_1_1 != nullptr) {
+ MYLOGI("Using IDumpstateDevice v1.1");
+ descriptor_to_kill = IDumpstateDevice_1_1::descriptor;
+ dumpstate_board_task = DumpstateBoardTask([this, dumpstate_device_1_1, &handle]() -> bool {
+ ::android::hardware::Return<DumpstateStatus> status =
+ dumpstate_device_1_1->dumpstateBoard_1_1(handle.get(), options_->dumpstate_hal_mode,
+ SEC_TO_MSEC(timeout_sec));
+ if (!status.isOk()) {
+ MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
+ return false;
+ } else if (status != DumpstateStatus::OK) {
+ MYLOGE("dumpstateBoard failed with DumpstateStatus::%s\n", toString(status).c_str());
+ return false;
+ }
+ return true;
+ });
+ } else {
+ MYLOGI("Using IDumpstateDevice v1.0");
+ descriptor_to_kill = IDumpstateDevice_1_0::descriptor;
+ dumpstate_board_task = DumpstateBoardTask([dumpstate_device_1_0, &handle]() -> bool {
+ ::android::hardware::Return<void> status =
+ dumpstate_device_1_0->dumpstateBoard(handle.get());
if (!status.isOk()) {
MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
return false;
}
return true;
});
+ }
+ auto result = dumpstate_board_task.get_future();
+ std::thread(std::move(dumpstate_board_task)).detach();
- auto result = dumpstate_task.get_future();
- std::thread(std::move(dumpstate_task)).detach();
-
- constexpr size_t timeout_sec = 30;
if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) {
MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate vendor HAL\n", timeout_sec);
- if (!android::base::SetProperty("ctl.interface_restart",
- android::base::StringPrintf("%s/default",
- IDumpstateDevice::descriptor))) {
+ if (!android::base::SetProperty(
+ "ctl.interface_restart",
+ android::base::StringPrintf("%s/default", descriptor_to_kill))) {
MYLOGE("Couldn't restart dumpstate HAL\n");
}
}
@@ -1978,15 +2009,14 @@
continue;
}
AddZipEntry(kDumpstateBoardFiles[i], paths[i]);
+ printf("*** See %s entry ***\n", kDumpstateBoardFiles[i].c_str());
}
-
- printf("*** See dumpstate-board.txt entry ***\n");
}
static void ShowUsage() {
fprintf(stderr,
"usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-d] [-p] "
- "[-z]] [-s] [-S] [-q] [-P] [-R] [-V version]\n"
+ "[-z] [-s] [-S] [-q] [-P] [-R] [-V version]\n"
" -h: display this help message\n"
" -b: play sound file instead of vibrate, at beginning of job\n"
" -e: play sound file instead of vibrate, at end of job\n"
@@ -2196,33 +2226,40 @@
switch (mode) {
case Dumpstate::BugreportMode::BUGREPORT_FULL:
options->do_fb = true;
+ options->dumpstate_hal_mode = DumpstateMode::FULL;
break;
case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
// Currently, the dumpstate binder is only used by Shell to update progress.
options->do_start_service = true;
options->do_progress_updates = true;
options->do_fb = false;
+ options->dumpstate_hal_mode = DumpstateMode::INTERACTIVE;
break;
case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
options->do_vibrate = false;
options->is_remote_mode = true;
options->do_fb = false;
+ options->dumpstate_hal_mode = DumpstateMode::REMOTE;
break;
case Dumpstate::BugreportMode::BUGREPORT_WEAR:
options->do_start_service = true;
options->do_progress_updates = true;
options->do_zip_file = true;
options->do_fb = true;
+ options->dumpstate_hal_mode = DumpstateMode::WEAR;
break;
+ // TODO(b/148168577) rename TELEPHONY everywhere to CONNECTIVITY.
case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
options->telephony_only = true;
options->do_progress_updates = true;
options->do_fb = false;
+ options->dumpstate_hal_mode = DumpstateMode::CONNECTIVITY;
break;
case Dumpstate::BugreportMode::BUGREPORT_WIFI:
options->wifi_only = true;
options->do_zip_file = true;
options->do_fb = false;
+ options->dumpstate_hal_mode = DumpstateMode::WIFI;
break;
case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
break;
@@ -2233,11 +2270,13 @@
MYLOGI(
"do_zip_file: %d do_vibrate: %d use_socket: %d use_control_socket: %d do_fb: %d "
"is_remote_mode: %d show_header_only: %d do_start_service: %d telephony_only: %d "
- "wifi_only: %d do_progress_updates: %d fd: %d bugreport_mode: %s args: %s\n",
+ "wifi_only: %d do_progress_updates: %d fd: %d bugreport_mode: %s dumpstate_hal_mode: %s "
+ "args: %s\n",
options.do_zip_file, options.do_vibrate, options.use_socket, options.use_control_socket,
options.do_fb, options.is_remote_mode, options.show_header_only, options.do_start_service,
options.telephony_only, options.wifi_only, options.do_progress_updates,
- options.bugreport_fd.get(), options.bugreport_mode.c_str(), options.args.c_str());
+ options.bugreport_fd.get(), options.bugreport_mode.c_str(),
+ toString(options.dumpstate_hal_mode).c_str(), options.args.c_str());
}
void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode,
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 7d9b113..111c098 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -27,6 +27,7 @@
#include <android-base/macros.h>
#include <android-base/unique_fd.h>
+#include <android/hardware/dumpstate/1.1/types.h>
#include <android/os/BnIncidentAuthListener.h>
#include <android/os/IDumpstate.h>
#include <android/os/IDumpstateListener.h>
@@ -366,6 +367,11 @@
bool wifi_only = false;
// Whether progress updates should be published.
bool do_progress_updates = false;
+ // The mode we'll use when calling IDumpstateDevice::dumpstateBoard.
+ // TODO(b/148168577) get rid of the AIDL values, replace them with the HAL values instead.
+ // The HAL is actually an API surface that can be validated, while the AIDL is not (@hide).
+ ::android::hardware::dumpstate::V1_1::DumpstateMode dumpstate_hal_mode =
+ ::android::hardware::dumpstate::V1_1::DumpstateMode::DEFAULT;
// File descriptor to output zip file.
android::base::unique_fd bugreport_fd;
// File descriptor to screenshot file.
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index 718f459..76b9960 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -36,20 +36,22 @@
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
-#include <cutils/properties.h>
#include <android-base/unique_fd.h>
+#include <android/hardware/dumpstate/1.1/types.h>
+#include <cutils/properties.h>
namespace android {
namespace os {
namespace dumpstate {
+using ::android::hardware::dumpstate::V1_1::DumpstateMode;
using ::testing::EndsWith;
using ::testing::HasSubstr;
-using ::testing::IsNull;
using ::testing::IsEmpty;
+using ::testing::IsNull;
using ::testing::NotNull;
-using ::testing::StrEq;
using ::testing::StartsWith;
+using ::testing::StrEq;
using ::testing::Test;
using ::testing::internal::CaptureStderr;
using ::testing::internal::CaptureStdout;
@@ -174,6 +176,7 @@
EXPECT_FALSE(options_.do_fb);
EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
+ EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
}
TEST_F(DumpOptionsTest, InitializeAdbBugreport) {
@@ -200,6 +203,7 @@
EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
EXPECT_FALSE(options_.use_socket);
+ EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
}
TEST_F(DumpOptionsTest, InitializeAdbShellBugreport) {
@@ -224,6 +228,7 @@
EXPECT_FALSE(options_.do_fb);
EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
+ EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
}
TEST_F(DumpOptionsTest, InitializeFullBugReport) {
@@ -231,6 +236,7 @@
EXPECT_TRUE(options_.do_add_date);
EXPECT_TRUE(options_.do_fb);
EXPECT_TRUE(options_.do_zip_file);
+ EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::FULL);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -249,6 +255,7 @@
EXPECT_TRUE(options_.do_progress_updates);
EXPECT_TRUE(options_.do_start_service);
EXPECT_FALSE(options_.do_fb);
+ EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::INTERACTIVE);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -265,6 +272,7 @@
EXPECT_TRUE(options_.is_remote_mode);
EXPECT_FALSE(options_.do_vibrate);
EXPECT_FALSE(options_.do_fb);
+ EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::REMOTE);
// Other options retain default values
EXPECT_FALSE(options_.use_control_socket);
@@ -280,6 +288,7 @@
EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.do_progress_updates);
EXPECT_TRUE(options_.do_start_service);
+ EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::WEAR);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -296,6 +305,7 @@
EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.telephony_only);
EXPECT_TRUE(options_.do_progress_updates);
+ EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::CONNECTIVITY);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -311,6 +321,7 @@
EXPECT_FALSE(options_.do_fb);
EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.wifi_only);
+ EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::WIFI);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -337,6 +348,7 @@
EXPECT_TRUE(options_.do_add_date);
EXPECT_TRUE(options_.do_fb);
EXPECT_TRUE(options_.do_zip_file);
+ EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -375,6 +387,7 @@
EXPECT_FALSE(options_.do_fb);
EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
+ EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
}
TEST_F(DumpOptionsTest, InitializePartial2) {
@@ -403,6 +416,7 @@
EXPECT_FALSE(options_.do_zip_file);
EXPECT_FALSE(options_.use_socket);
EXPECT_FALSE(options_.use_control_socket);
+ EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
}
TEST_F(DumpOptionsTest, InitializeHelp) {
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 08d4657..4288735 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -2684,7 +2684,7 @@
}
// Mount volume's CE and DE storage to mirror
-binder::Status InstalldNativeService::onPrivateVolumeMounted(
+binder::Status InstalldNativeService::tryMountDataMirror(
const std::unique_ptr<std::string>& uuid) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
@@ -2696,24 +2696,50 @@
}
const char* uuid_ = uuid->c_str();
- // Mount CE mirror
+
std::string mirrorVolCePath(StringPrintf("%s/%s", kDataMirrorCePath, uuid_));
std::lock_guard<std::recursive_mutex> lock(mLock);
- if (fs_prepare_dir(mirrorVolCePath.c_str(), 0700, AID_ROOT, AID_ROOT) != 0) {
+ if (fs_prepare_dir(mirrorVolCePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) {
return error("Failed to create CE mirror");
}
- auto cePath = StringPrintf("%s/user_ce", create_data_path(uuid_).c_str());
+
+ std::string mirrorVolDePath(StringPrintf("%s/%s", kDataMirrorDePath, uuid_));
+ if (fs_prepare_dir(mirrorVolDePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) {
+ return error("Failed to create DE mirror");
+ }
+
+ auto cePath = StringPrintf("%s/user", create_data_path(uuid_).c_str());
+ auto dePath = StringPrintf("%s/user_de", create_data_path(uuid_).c_str());
+
+ if (access(cePath.c_str(), F_OK) != 0) {
+ return error("Cannot access CE path: " + cePath);
+ }
+ if (access(dePath.c_str(), F_OK) != 0) {
+ return error("Cannot access DE path: " + dePath);
+ }
+
+ struct stat ceStat, mirrorCeStat;
+ if (stat(cePath.c_str(), &ceStat) != 0) {
+ return error("Failed to stat " + cePath);
+ }
+ if (stat(mirrorVolCePath.c_str(), &mirrorCeStat) != 0) {
+ return error("Failed to stat " + mirrorVolCePath);
+ }
+
+ if (mirrorCeStat.st_ino == ceStat.st_ino) {
+ // As it's being called by prepareUserStorage, it can be called multiple times.
+ // Hence, we if we mount it already, we should skip it.
+ LOG(WARNING) << "CE dir is mounted already: " + cePath;
+ return ok();
+ }
+
+ // Mount CE mirror
if (TEMP_FAILURE_RETRY(mount(cePath.c_str(), mirrorVolCePath.c_str(), NULL,
MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC, nullptr)) == -1) {
return error("Failed to mount " + mirrorVolCePath);
}
// Mount DE mirror
- std::string mirrorVolDePath(StringPrintf("%s/%s", kDataMirrorDePath, uuid_));
- if (fs_prepare_dir(mirrorVolDePath.c_str(), 0700, AID_ROOT, AID_ROOT) != 0) {
- return error("Failed to create DE mirror");
- }
- auto dePath = StringPrintf("%s/user_de", create_data_path(uuid_).c_str());
if (TEMP_FAILURE_RETRY(mount(dePath.c_str(), mirrorVolDePath.c_str(), NULL,
MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC, nullptr)) == -1) {
return error("Failed to mount " + mirrorVolDePath);
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index eb35fd3..27c59b0 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -155,7 +155,7 @@
binder::Status invalidateMounts();
binder::Status isQuotaSupported(const std::unique_ptr<std::string>& volumeUuid,
bool* _aidl_return);
- binder::Status onPrivateVolumeMounted(const std::unique_ptr<std::string>& volumeUuid);
+ binder::Status tryMountDataMirror(const std::unique_ptr<std::string>& volumeUuid);
binder::Status onPrivateVolumeRemoved(const std::unique_ptr<std::string>& volumeUuid);
binder::Status prepareAppProfile(const std::string& packageName,
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 80d9703..f2e86ba 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -116,7 +116,7 @@
int appId, @utf8InCpp String seInfo, int user, int snapshotId, int storageflags);
void destroyAppDataSnapshot(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
int userId, long ceSnapshotInode, int snapshotId, int storageFlags);
- void onPrivateVolumeMounted(@nullable @utf8InCpp String volumeUuid);
+ void tryMountDataMirror(@nullable @utf8InCpp String volumeUuid);
void onPrivateVolumeRemoved(@nullable @utf8InCpp String volumeUuid);
void migrateLegacyObbData();
diff --git a/include/input/Input.h b/include/input/Input.h
index cf0814c..14a7288 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -73,6 +73,19 @@
AMOTION_EVENT_FLAG_TAINTED = 0x80000000,
};
+/**
+ * Allowed VerifiedKeyEvent flags. All other flags from KeyEvent do not get verified.
+ * These values must be kept in sync with VerifiedKeyEvent.java
+ */
+constexpr int32_t VERIFIED_KEY_EVENT_FLAGS = AKEY_EVENT_FLAG_CANCELED;
+
+/**
+ * Allowed VerifiedMotionEventFlags. All other flags from MotionEvent do not get verified.
+ * These values must be kept in sync with VerifiedMotionEvent.java
+ */
+constexpr int32_t VERIFIED_MOTION_EVENT_FLAGS =
+ AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
+
enum {
/* Used when a motion event is not associated with any display.
* Typically used for non-pointer events. */
@@ -718,6 +731,55 @@
bool mInTouchMode;
};
+/**
+ * Base class for verified events.
+ * Do not create a VerifiedInputEvent explicitly.
+ * Use helper functions to create them from InputEvents.
+ */
+struct __attribute__((__packed__)) VerifiedInputEvent {
+ enum class Type : int32_t {
+ KEY = AINPUT_EVENT_TYPE_KEY,
+ MOTION = AINPUT_EVENT_TYPE_MOTION,
+ };
+
+ Type type;
+ int32_t deviceId;
+ nsecs_t eventTimeNanos;
+ uint32_t source;
+ int32_t displayId;
+};
+
+/**
+ * Same as KeyEvent, but only contains the data that can be verified.
+ * If you update this class, you must also update VerifiedKeyEvent.java
+ */
+struct __attribute__((__packed__)) VerifiedKeyEvent : public VerifiedInputEvent {
+ int32_t action;
+ nsecs_t downTimeNanos;
+ int32_t flags;
+ int32_t keyCode;
+ int32_t scanCode;
+ int32_t metaState;
+ int32_t repeatCount;
+};
+
+/**
+ * Same as MotionEvent, but only contains the data that can be verified.
+ * If you update this class, you must also update VerifiedMotionEvent.java
+ */
+struct __attribute__((__packed__)) VerifiedMotionEvent : public VerifiedInputEvent {
+ float rawX;
+ float rawY;
+ int32_t actionMasked;
+ nsecs_t downTimeNanos;
+ int32_t flags;
+ int32_t metaState;
+ int32_t buttonState;
+};
+
+VerifiedKeyEvent verifiedKeyEventFromKeyEvent(const KeyEvent& event);
+VerifiedMotionEvent verifiedMotionEventFromMotionEvent(const MotionEvent& event);
+
/*
* Input event factory.
*/
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 5a7f9a9..3ee8187 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -40,7 +40,7 @@
},
srcs: ["binderDriverInterfaceTest.cpp"],
- test_suites: ["device-tests"],
+ test_suites: ["device-tests", "vts-core"],
}
cc_test {
@@ -69,7 +69,7 @@
"libbinder",
"libutils",
],
- test_suites: ["device-tests"],
+ test_suites: ["device-tests", "vts-core"],
require_root: true,
}
@@ -131,7 +131,7 @@
"liblog",
"libutils",
],
- test_suites: ["device-tests"],
+ test_suites: ["device-tests", "vts-core"],
require_root: true,
}
diff --git a/libs/binderthreadstate/Android.bp b/libs/binderthreadstate/Android.bp
index 4655e1d..c186110 100644
--- a/libs/binderthreadstate/Android.bp
+++ b/libs/binderthreadstate/Android.bp
@@ -63,15 +63,3 @@
],
require_root: true,
}
-
-// TODO(b/148692216): remove empty lib
-cc_library {
- name: "libbinderthreadstate",
- recovery_available: true,
- vendor_available: false,
- vndk: {
- enabled: true,
- support_system_process: true,
- },
- host_supported: true,
-}
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index 31a399b..b6b81bb 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -58,6 +58,7 @@
static std::set<uint32_t> gAllFreqs;
static unique_fd gTisMapFd;
static unique_fd gConcurrentMapFd;
+static unique_fd gUidLastUpdateMapFd;
static std::optional<std::vector<uint32_t>> readNumbersFromFile(const std::string &path) {
std::string data;
@@ -144,6 +145,10 @@
unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_concurrent_times_map")};
if (gConcurrentMapFd < 0) return false;
+ gUidLastUpdateMapFd =
+ unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_last_update_map")};
+ if (gUidLastUpdateMapFd < 0) return false;
+
gInitialized = true;
return true;
}
@@ -263,6 +268,18 @@
return out;
}
+static std::optional<bool> uidUpdatedSince(uint32_t uid, uint64_t lastUpdate,
+ uint64_t *newLastUpdate) {
+ uint64_t uidLastUpdate;
+ if (findMapEntry(gUidLastUpdateMapFd, &uid, &uidLastUpdate)) return {};
+ // Updates that occurred during the previous read may have been missed. To mitigate
+ // this, don't ignore entries updated up to 1s before *lastUpdate
+ constexpr uint64_t NSEC_PER_SEC = 1000000000;
+ if (uidLastUpdate + NSEC_PER_SEC < lastUpdate) return false;
+ if (uidLastUpdate > *newLastUpdate) *newLastUpdate = uidLastUpdate;
+ return true;
+}
+
// Retrieve the times in ns that each uid spent running at each CPU freq.
// Return contains no value on error, otherwise it contains a map from uids to vectors of vectors
// using the format:
@@ -271,6 +288,14 @@
// where ti_j_k is the ns uid i spent running on the jth cluster at the cluster's kth lowest freq.
std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>>
getUidsCpuFreqTimes() {
+ return getUidsUpdatedCpuFreqTimes(nullptr);
+}
+
+// Retrieve the times in ns that each uid spent running at each CPU freq, excluding UIDs that have
+// not run since before lastUpdate.
+// Return format is the same as getUidsCpuFreqTimes()
+std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>>
+getUidsUpdatedCpuFreqTimes(uint64_t *lastUpdate) {
if (!gInitialized && !initGlobals()) return {};
time_key_t key, prevKey;
std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> map;
@@ -282,8 +307,14 @@
std::vector<std::vector<uint64_t>> mapFormat;
for (const auto &freqList : gPolicyFreqs) mapFormat.emplace_back(freqList.size(), 0);
+ uint64_t newLastUpdate = lastUpdate ? *lastUpdate : 0;
std::vector<tis_val_t> vals(gNCpus);
do {
+ if (lastUpdate) {
+ auto uidUpdated = uidUpdatedSince(key.uid, *lastUpdate, &newLastUpdate);
+ if (!uidUpdated.has_value()) return {};
+ if (!*uidUpdated) continue;
+ }
if (findMapEntry(gTisMapFd, &key, vals.data())) return {};
if (map.find(key.uid) == map.end()) map.emplace(key.uid, mapFormat);
@@ -299,8 +330,9 @@
}
}
prevKey = key;
- } while (!getNextMapKey(gTisMapFd, &prevKey, &key));
+ } while (prevKey = key, !getNextMapKey(gTisMapFd, &prevKey, &key));
if (errno != ENOENT) return {};
+ if (lastUpdate && newLastUpdate > *lastUpdate) *lastUpdate = newLastUpdate;
return map;
}
@@ -365,6 +397,15 @@
// where ai is the ns spent running concurrently with tasks on i other cpus and pi_j is the ns spent
// running on the ith cluster, concurrently with tasks on j other cpus in the same cluster.
std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsConcurrentTimes() {
+ return getUidsUpdatedConcurrentTimes(nullptr);
+}
+
+// Retrieve the times in ns that each uid spent running concurrently with each possible number of
+// other tasks on each cluster (policy times) and overall (active times), excluding UIDs that have
+// not run since before lastUpdate.
+// Return format is the same as getUidsConcurrentTimes()
+std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsUpdatedConcurrentTimes(
+ uint64_t *lastUpdate) {
if (!gInitialized && !initGlobals()) return {};
time_key_t key, prevKey;
std::unordered_map<uint32_t, concurrent_time_t> ret;
@@ -379,7 +420,13 @@
std::vector<concurrent_val_t> vals(gNCpus);
std::vector<uint64_t>::iterator activeBegin, activeEnd, policyBegin, policyEnd;
+ uint64_t newLastUpdate = lastUpdate ? *lastUpdate : 0;
do {
+ if (lastUpdate) {
+ auto uidUpdated = uidUpdatedSince(key.uid, *lastUpdate, &newLastUpdate);
+ if (!uidUpdated.has_value()) return {};
+ if (!*uidUpdated) continue;
+ }
if (findMapEntry(gConcurrentMapFd, &key, vals.data())) return {};
if (ret.find(key.uid) == ret.end()) ret.emplace(key.uid, retFormat);
@@ -405,8 +452,7 @@
std::plus<uint64_t>());
}
}
- prevKey = key;
- } while (!getNextMapKey(gConcurrentMapFd, &prevKey, &key));
+ } while (prevKey = key, !getNextMapKey(gConcurrentMapFd, &prevKey, &key));
if (errno != ENOENT) return {};
for (const auto &[key, value] : ret) {
if (!verifyConcurrentTimes(value)) {
@@ -414,6 +460,7 @@
if (val.has_value()) ret[key] = val.value();
}
}
+ if (lastUpdate && newLastUpdate > *lastUpdate) *lastUpdate = newLastUpdate;
return ret;
}
@@ -446,6 +493,8 @@
return false;
if (deleteMapEntry(gConcurrentMapFd, &key) && errno != ENOENT) return false;
}
+
+ if (deleteMapEntry(gUidLastUpdateMapFd, &uid) && errno != ENOENT) return false;
return true;
}
diff --git a/libs/cputimeinstate/cputimeinstate.h b/libs/cputimeinstate/cputimeinstate.h
index 49469d8..b7600f5 100644
--- a/libs/cputimeinstate/cputimeinstate.h
+++ b/libs/cputimeinstate/cputimeinstate.h
@@ -26,6 +26,8 @@
std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t uid);
std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>>
getUidsCpuFreqTimes();
+std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>>
+ getUidsUpdatedCpuFreqTimes(uint64_t *lastUpdate);
std::optional<std::vector<std::vector<uint32_t>>> getCpuFreqs();
struct concurrent_time_t {
@@ -35,6 +37,8 @@
std::optional<concurrent_time_t> getUidConcurrentTimes(uint32_t uid, bool retry = true);
std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsConcurrentTimes();
+std::optional<std::unordered_map<uint32_t, concurrent_time_t>>
+ getUidsUpdatedConcurrentTimes(uint64_t *lastUpdate);
bool clearUidTimes(unsigned int uid);
} // namespace bpf
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index 23d87fd..ea2a200 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -115,71 +115,169 @@
}
TEST(TimeInStateTest, AllUidTimeInState) {
- vector<size_t> sizes;
- auto map = getUidsCpuFreqTimes();
- ASSERT_TRUE(map.has_value());
+ uint64_t zero = 0;
+ auto maps = {getUidsCpuFreqTimes(), getUidsUpdatedCpuFreqTimes(&zero)};
+ for (const auto &map : maps) {
+ ASSERT_TRUE(map.has_value());
- ASSERT_FALSE(map->empty());
+ ASSERT_FALSE(map->empty());
- auto firstEntry = map->begin()->second;
- for (const auto &subEntry : firstEntry) sizes.emplace_back(subEntry.size());
+ vector<size_t> sizes;
+ auto firstEntry = map->begin()->second;
+ for (const auto &subEntry : firstEntry) sizes.emplace_back(subEntry.size());
- for (const auto &vec : *map) {
- ASSERT_EQ(vec.second.size(), sizes.size());
- for (size_t i = 0; i < vec.second.size(); ++i) ASSERT_EQ(vec.second[i].size(), sizes[i]);
+ for (const auto &vec : *map) {
+ ASSERT_EQ(vec.second.size(), sizes.size());
+ for (size_t i = 0; i < vec.second.size(); ++i) ASSERT_EQ(vec.second[i].size(), sizes[i]);
+ }
+ }
+}
+
+void TestCheckUpdate(const std::vector<std::vector<uint64_t>> &before,
+ const std::vector<std::vector<uint64_t>> &after) {
+ ASSERT_EQ(before.size(), after.size());
+ uint64_t sumBefore = 0, sumAfter = 0;
+ for (size_t i = 0; i < before.size(); ++i) {
+ ASSERT_EQ(before[i].size(), after[i].size());
+ for (size_t j = 0; j < before[i].size(); ++j) {
+ // Times should never decrease
+ ASSERT_LE(before[i][j], after[i][j]);
+ }
+ sumBefore += std::accumulate(before[i].begin(), before[i].end(), (uint64_t)0);
+ sumAfter += std::accumulate(after[i].begin(), after[i].end(), (uint64_t)0);
+ }
+ ASSERT_LE(sumBefore, sumAfter);
+ ASSERT_LE(sumAfter - sumBefore, NSEC_PER_SEC);
+}
+
+TEST(TimeInStateTest, AllUidUpdatedTimeInState) {
+ uint64_t lastUpdate = 0;
+ auto map1 = getUidsUpdatedCpuFreqTimes(&lastUpdate);
+ ASSERT_TRUE(map1.has_value());
+ ASSERT_FALSE(map1->empty());
+ ASSERT_NE(lastUpdate, (uint64_t)0);
+ uint64_t oldLastUpdate = lastUpdate;
+
+ // Sleep briefly to trigger a context switch, ensuring we see at least one update.
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000;
+ nanosleep (&ts, NULL);
+
+ auto map2 = getUidsUpdatedCpuFreqTimes(&lastUpdate);
+ ASSERT_TRUE(map2.has_value());
+ ASSERT_FALSE(map2->empty());
+ ASSERT_NE(lastUpdate, oldLastUpdate);
+
+ bool someUidsExcluded = false;
+ for (const auto &[uid, v] : *map1) {
+ if (map2->find(uid) == map2->end()) {
+ someUidsExcluded = true;
+ break;
+ }
+ }
+ ASSERT_TRUE(someUidsExcluded);
+
+ for (const auto &[uid, newTimes] : *map2) {
+ ASSERT_NE(map1->find(uid), map1->end());
+ ASSERT_NO_FATAL_FAILURE(TestCheckUpdate((*map1)[uid], newTimes));
}
}
TEST(TimeInStateTest, SingleAndAllUidTimeInStateConsistent) {
- auto map = getUidsCpuFreqTimes();
- ASSERT_TRUE(map.has_value());
- ASSERT_FALSE(map->empty());
+ uint64_t zero = 0;
+ auto maps = {getUidsCpuFreqTimes(), getUidsUpdatedCpuFreqTimes(&zero)};
+ for (const auto &map : maps) {
+ ASSERT_TRUE(map.has_value());
+ ASSERT_FALSE(map->empty());
- for (const auto &kv : *map) {
- uint32_t uid = kv.first;
- auto times1 = kv.second;
- auto times2 = getUidCpuFreqTimes(uid);
- ASSERT_TRUE(times2.has_value());
+ for (const auto &kv : *map) {
+ uint32_t uid = kv.first;
+ auto times1 = kv.second;
+ auto times2 = getUidCpuFreqTimes(uid);
+ ASSERT_TRUE(times2.has_value());
- ASSERT_EQ(times1.size(), times2->size());
- for (uint32_t i = 0; i < times1.size(); ++i) {
- ASSERT_EQ(times1[i].size(), (*times2)[i].size());
- for (uint32_t j = 0; j < times1[i].size(); ++j) {
- ASSERT_LE((*times2)[i][j] - times1[i][j], NSEC_PER_SEC);
+ ASSERT_EQ(times1.size(), times2->size());
+ for (uint32_t i = 0; i < times1.size(); ++i) {
+ ASSERT_EQ(times1[i].size(), (*times2)[i].size());
+ for (uint32_t j = 0; j < times1[i].size(); ++j) {
+ ASSERT_LE((*times2)[i][j] - times1[i][j], NSEC_PER_SEC);
+ }
}
}
}
}
TEST(TimeInStateTest, AllUidConcurrentTimes) {
- auto map = getUidsConcurrentTimes();
- ASSERT_TRUE(map.has_value());
- ASSERT_FALSE(map->empty());
+ uint64_t zero = 0;
+ auto maps = {getUidsConcurrentTimes(), getUidsUpdatedConcurrentTimes(&zero)};
+ for (const auto &map : maps) {
+ ASSERT_TRUE(map.has_value());
+ ASSERT_FALSE(map->empty());
- auto firstEntry = map->begin()->second;
- for (const auto &kv : *map) {
- ASSERT_EQ(kv.second.active.size(), firstEntry.active.size());
- ASSERT_EQ(kv.second.policy.size(), firstEntry.policy.size());
- for (size_t i = 0; i < kv.second.policy.size(); ++i) {
- ASSERT_EQ(kv.second.policy[i].size(), firstEntry.policy[i].size());
+ auto firstEntry = map->begin()->second;
+ for (const auto &kv : *map) {
+ ASSERT_EQ(kv.second.active.size(), firstEntry.active.size());
+ ASSERT_EQ(kv.second.policy.size(), firstEntry.policy.size());
+ for (size_t i = 0; i < kv.second.policy.size(); ++i) {
+ ASSERT_EQ(kv.second.policy[i].size(), firstEntry.policy[i].size());
+ }
}
}
}
-TEST(TimeInStateTest, SingleAndAllUidConcurrentTimesConsistent) {
- auto map = getUidsConcurrentTimes();
- ASSERT_TRUE(map.has_value());
- for (const auto &kv : *map) {
- uint32_t uid = kv.first;
- auto times1 = kv.second;
- auto times2 = getUidConcurrentTimes(uid);
- ASSERT_TRUE(times2.has_value());
- for (uint32_t i = 0; i < times1.active.size(); ++i) {
- ASSERT_LE(times2->active[i] - times1.active[i], NSEC_PER_SEC);
+TEST(TimeInStateTest, AllUidUpdatedConcurrentTimes) {
+ uint64_t lastUpdate = 0;
+ auto map1 = getUidsUpdatedConcurrentTimes(&lastUpdate);
+ ASSERT_TRUE(map1.has_value());
+ ASSERT_FALSE(map1->empty());
+ ASSERT_NE(lastUpdate, (uint64_t)0);
+
+ // Sleep briefly to trigger a context switch, ensuring we see at least one update.
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000;
+ nanosleep (&ts, NULL);
+
+ uint64_t oldLastUpdate = lastUpdate;
+ auto map2 = getUidsUpdatedConcurrentTimes(&lastUpdate);
+ ASSERT_TRUE(map2.has_value());
+ ASSERT_FALSE(map2->empty());
+ ASSERT_NE(lastUpdate, oldLastUpdate);
+
+ bool someUidsExcluded = false;
+ for (const auto &[uid, v] : *map1) {
+ if (map2->find(uid) == map2->end()) {
+ someUidsExcluded = true;
+ break;
}
- for (uint32_t i = 0; i < times1.policy.size(); ++i) {
- for (uint32_t j = 0; j < times1.policy[i].size(); ++j) {
- ASSERT_LE(times2->policy[i][j] - times1.policy[i][j], NSEC_PER_SEC);
+ }
+ ASSERT_TRUE(someUidsExcluded);
+
+ for (const auto &[uid, newTimes] : *map2) {
+ ASSERT_NE(map1->find(uid), map1->end());
+ ASSERT_NO_FATAL_FAILURE(TestCheckUpdate({(*map1)[uid].active},{newTimes.active}));
+ ASSERT_NO_FATAL_FAILURE(TestCheckUpdate((*map1)[uid].policy, newTimes.policy));
+ }
+}
+
+TEST(TimeInStateTest, SingleAndAllUidConcurrentTimesConsistent) {
+ uint64_t zero = 0;
+ auto maps = {getUidsConcurrentTimes(), getUidsUpdatedConcurrentTimes(&zero)};
+ for (const auto &map : maps) {
+ ASSERT_TRUE(map.has_value());
+ for (const auto &kv : *map) {
+ uint32_t uid = kv.first;
+ auto times1 = kv.second;
+ auto times2 = getUidConcurrentTimes(uid);
+ ASSERT_TRUE(times2.has_value());
+ for (uint32_t i = 0; i < times1.active.size(); ++i) {
+ ASSERT_LE(times2->active[i] - times1.active[i], NSEC_PER_SEC);
+ }
+ for (uint32_t i = 0; i < times1.policy.size(); ++i) {
+ for (uint32_t j = 0; j < times1.policy[i].size(); ++j) {
+ ASSERT_LE(times2->policy[i][j] - times1.policy[i][j], NSEC_PER_SEC);
+ }
}
}
}
@@ -242,45 +340,51 @@
}
TEST(TimeInStateTest, AllUidTimeInStateSanityCheck) {
- auto map = getUidsCpuFreqTimes();
- ASSERT_TRUE(map.has_value());
+ uint64_t zero = 0;
+ auto maps = {getUidsCpuFreqTimes(), getUidsUpdatedCpuFreqTimes(&zero)};
+ for (const auto &map : maps) {
+ ASSERT_TRUE(map.has_value());
- bool foundLargeValue = false;
- for (const auto &kv : *map) {
- for (const auto &timeVec : kv.second) {
- for (const auto &time : timeVec) {
- ASSERT_LE(time, NSEC_PER_YEAR);
- if (time > UINT32_MAX) foundLargeValue = true;
+ bool foundLargeValue = false;
+ for (const auto &kv : *map) {
+ for (const auto &timeVec : kv.second) {
+ for (const auto &time : timeVec) {
+ ASSERT_LE(time, NSEC_PER_YEAR);
+ if (time > UINT32_MAX) foundLargeValue = true;
+ }
}
}
+ // UINT32_MAX nanoseconds is less than 5 seconds, so if every part of our pipeline is using
+ // uint64_t as expected, we should have some times higher than that.
+ ASSERT_TRUE(foundLargeValue);
}
- // UINT32_MAX nanoseconds is less than 5 seconds, so if every part of our pipeline is using
- // uint64_t as expected, we should have some times higher than that.
- ASSERT_TRUE(foundLargeValue);
}
TEST(TimeInStateTest, AllUidConcurrentTimesSanityCheck) {
- auto concurrentMap = getUidsConcurrentTimes();
- ASSERT_TRUE(concurrentMap);
+ uint64_t zero = 0;
+ auto maps = {getUidsConcurrentTimes(), getUidsUpdatedConcurrentTimes(&zero)};
+ for (const auto &concurrentMap : maps) {
+ ASSERT_TRUE(concurrentMap);
- bool activeFoundLargeValue = false;
- bool policyFoundLargeValue = false;
- for (const auto &kv : *concurrentMap) {
- for (const auto &time : kv.second.active) {
- ASSERT_LE(time, NSEC_PER_YEAR);
- if (time > UINT32_MAX) activeFoundLargeValue = true;
- }
- for (const auto &policyTimeVec : kv.second.policy) {
- for (const auto &time : policyTimeVec) {
+ bool activeFoundLargeValue = false;
+ bool policyFoundLargeValue = false;
+ for (const auto &kv : *concurrentMap) {
+ for (const auto &time : kv.second.active) {
ASSERT_LE(time, NSEC_PER_YEAR);
- if (time > UINT32_MAX) policyFoundLargeValue = true;
+ if (time > UINT32_MAX) activeFoundLargeValue = true;
+ }
+ for (const auto &policyTimeVec : kv.second.policy) {
+ for (const auto &time : policyTimeVec) {
+ ASSERT_LE(time, NSEC_PER_YEAR);
+ if (time > UINT32_MAX) policyFoundLargeValue = true;
+ }
}
}
+ // UINT32_MAX nanoseconds is less than 5 seconds, so if every part of our pipeline is using
+ // uint64_t as expected, we should have some times higher than that.
+ ASSERT_TRUE(activeFoundLargeValue);
+ ASSERT_TRUE(policyFoundLargeValue);
}
- // UINT32_MAX nanoseconds is less than 5 seconds, so if every part of our pipeline is using
- // uint64_t as expected, we should have some times higher than that.
- ASSERT_TRUE(activeFoundLargeValue);
- ASSERT_TRUE(policyFoundLargeValue);
}
TEST(TimeInStateTest, AllUidTimesConsistent) {
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index e2f5d31..f6493bf 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -174,7 +174,9 @@
}
mPendingReleaseItem.item = std::move(mSubmitted.front());
mSubmitted.pop();
- processNextBufferLocked();
+ if (mNextTransaction == nullptr) {
+ processNextBufferLocked();
+ }
mCallbackCV.notify_all();
decStrong((void*)transactionCallbackThunk);
}
@@ -252,8 +254,13 @@
void BLASTBufferQueue::onFrameAvailable(const BufferItem& /*item*/) {
ATRACE_CALL();
- std::lock_guard _lock{mMutex};
+ std::unique_lock _lock{mMutex};
+ if (mNextTransaction != nullptr) {
+ while (mNumFrameAvailable > 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS) {
+ mCallbackCV.wait(_lock);
+ }
+ }
// add to shadow queue
mNumFrameAvailable++;
processNextBufferLocked();
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 23532e7..278cc59 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -1180,6 +1180,9 @@
allocateBuffers();
res = NO_ERROR;
break;
+ case NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER:
+ res = dispatchGetLastQueuedBuffer(args);
+ break;
default:
res = NAME_NOT_FOUND;
break;
@@ -1452,6 +1455,30 @@
return NO_ERROR;
}
+int Surface::dispatchGetLastQueuedBuffer(va_list args) {
+ AHardwareBuffer** buffer = va_arg(args, AHardwareBuffer**);
+ int* fence = va_arg(args, int*);
+ float* matrix = va_arg(args, float*);
+ sp<GraphicBuffer> graphicBuffer;
+ sp<Fence> spFence;
+
+ int result = mGraphicBufferProducer->getLastQueuedBuffer(&graphicBuffer, &spFence, matrix);
+
+ if (graphicBuffer != nullptr) {
+ *buffer = reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get());
+ AHardwareBuffer_acquire(*buffer);
+ } else {
+ *buffer = nullptr;
+ }
+
+ if (spFence != nullptr) {
+ *fence = spFence->dup();
+ } else {
+ *fence = -1;
+ }
+ return result;
+}
+
bool Surface::transformToDisplayInverse() {
return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) ==
NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
diff --git a/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp b/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp
index 0f3ae2e..c76d771 100644
--- a/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp
+++ b/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp
@@ -288,10 +288,12 @@
&bOutput),
&hStatus) &&
b2h(bOutput, &hOutput);
- if (converted) {
+#ifdef NO_BINDER
+ if (converted && hListener != nullptr) {
mObituary = new Obituary(this, hListener, hConnectionType);
hListener->linkToDeath(mObituary, 0);
}
+#endif // NO_BINDER
_hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR, hOutput);
return {};
}
@@ -304,10 +306,12 @@
}
HStatus hStatus{};
bool converted = b2h(mBase->disconnect(bConnectionType), &hStatus);
+#ifdef NO_BINDER
if (mObituary != nullptr) {
mObituary->listener->unlinkToDeath(mObituary);
mObituary.clear();
}
+#endif // NO_BINDER
return {converted ? hStatus : HStatus::UNKNOWN_ERROR};
}
diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h
index 2b65d2f..6366529 100644
--- a/libs/gui/include/gui/ISurfaceComposerClient.h
+++ b/libs/gui/include/gui/ISurfaceComposerClient.h
@@ -44,7 +44,7 @@
eCursorWindow = 0x00002000,
eFXSurfaceBufferQueue = 0x00000000,
- eFXSurfaceColor = 0x00020000,
+ eFXSurfaceEffect = 0x00020000,
eFXSurfaceBufferState = 0x00040000,
eFXSurfaceContainer = 0x00080000,
eFXSurfaceMask = 0x000F0000,
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 0139507..4a353fc 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -262,6 +262,7 @@
int dispatchAddDequeueInterceptor(va_list args);
int dispatchAddPerformInterceptor(va_list args);
int dispatchAddQueueInterceptor(va_list args);
+ int dispatchGetLastQueuedBuffer(va_list args);
bool transformToDisplayInverse();
protected:
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index e184c7f..a87ccd6 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -403,7 +403,7 @@
int32_t finalCropSideLength = bufferSideLength / 2;
auto bg = mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor);
+ ISurfaceComposerClient::eFXSurfaceEffect);
ASSERT_NE(nullptr, bg.get());
Transaction t;
t.setLayerStack(bg, 0)
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 1a623e2..c59afba 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -82,7 +82,8 @@
int width, int height) {
sp<SurfaceControl> surfaceControl =
scc->createSurface(String8("Test Surface"), 0 /* bufHeight */, 0 /* bufWidth */,
- PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor);
+ PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceEffect);
return std::make_unique<InputSurface>(surfaceControl, width, height);
}
diff --git a/libs/gui/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp
index c9de37d..dbd4ef9 100644
--- a/libs/gui/tests/RegionSampling_test.cpp
+++ b/libs/gui/tests/RegionSampling_test.cpp
@@ -183,7 +183,7 @@
mBackgroundLayer =
mSurfaceComposerClient->createSurface(String8("Background RegionSamplingTest"), 0,
0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor);
+ ISurfaceComposerClient::eFXSurfaceEffect);
uint32_t layerPositionBottom = 0x7E000000;
SurfaceComposerClient::Transaction{}
.setLayer(mBackgroundLayer, layerPositionBottom)
diff --git a/libs/gui/tests/SamplingDemo.cpp b/libs/gui/tests/SamplingDemo.cpp
index 9891587..5c1bebb 100644
--- a/libs/gui/tests/SamplingDemo.cpp
+++ b/libs/gui/tests/SamplingDemo.cpp
@@ -39,7 +39,7 @@
sp<SurfaceComposerClient> client = new SurfaceComposerClient;
mButton = client->createSurface(String8(name), 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor);
+ ISurfaceComposerClient::eFXSurfaceEffect);
const int32_t width = samplingArea.getWidth();
const int32_t height = samplingArea.getHeight();
@@ -55,7 +55,7 @@
.apply();
mButtonBlend = client->createSurface(String8(name) + "Blend", 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor);
+ ISurfaceComposerClient::eFXSurfaceEffect);
SurfaceComposerClient::Transaction{}
.setLayer(mButtonBlend, 0x7ffffffe)
@@ -73,7 +73,7 @@
if (HIGHLIGHT_SAMPLING_AREA) {
mSamplingArea =
client->createSurface(String8("SamplingArea"), 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor);
+ ISurfaceComposerClient::eFXSurfaceEffect);
SurfaceComposerClient::Transaction{}
.setLayer(mSamplingArea, 0x7ffffffd)
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 85b0fd0..2a73dc0 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -57,6 +57,30 @@
return "UNKNOWN";
}
+VerifiedKeyEvent verifiedKeyEventFromKeyEvent(const KeyEvent& event) {
+ return {{VerifiedInputEvent::Type::KEY, event.getDeviceId(), event.getEventTime(),
+ event.getSource(), event.getDisplayId()},
+ event.getAction(),
+ event.getDownTime(),
+ event.getFlags() & VERIFIED_KEY_EVENT_FLAGS,
+ event.getKeyCode(),
+ event.getScanCode(),
+ event.getMetaState(),
+ event.getRepeatCount()};
+}
+
+VerifiedMotionEvent verifiedMotionEventFromMotionEvent(const MotionEvent& event) {
+ return {{VerifiedInputEvent::Type::MOTION, event.getDeviceId(), event.getEventTime(),
+ event.getSource(), event.getDisplayId()},
+ event.getRawX(0),
+ event.getRawY(0),
+ event.getActionMasked(),
+ event.getDownTime(),
+ event.getFlags() & VERIFIED_MOTION_EVENT_FLAGS,
+ event.getMetaState(),
+ event.getButtonState()};
+}
+
void InputEvent::initialize(int32_t deviceId, uint32_t source, int32_t displayId,
std::array<uint8_t, 32> hmac) {
mDeviceId = deviceId;
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index c1c35e1..fb21d5e 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -10,12 +10,12 @@
"LatencyStatistics_test.cpp",
"TouchVideoFrame_test.cpp",
"VelocityTracker_test.cpp",
+ "VerifiedInputEvent_test.cpp",
],
cflags: [
"-Wall",
"-Wextra",
"-Werror",
- "-Wno-unused-variable",
],
shared_libs: [
"libinput",
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index dce1f29..d0f7618 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -46,7 +46,6 @@
}
TEST_F(PointerCoordsTest, AxisValues) {
- float* valuePtr;
PointerCoords coords;
coords.clear();
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index d4bbf6c..885196f 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -38,6 +38,7 @@
virtual void SetUp() {
status_t result = InputChannel::openInputChannelPair("channel name",
serverChannel, clientChannel);
+ ASSERT_EQ(OK, result);
mPublisher = new InputPublisher(serverChannel);
mConsumer = new InputConsumer(clientChannel);
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index aa8a2d4..dd127fc 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -98,4 +98,34 @@
static_assert(sizeof(InputMessage::Body::Focus) == 8);
}
+// --- VerifiedInputEvent ---
+// Ensure that VerifiedInputEvent, VerifiedKeyEvent, VerifiedMotionEvent are packed.
+// We will treat them as byte collections when signing them. There should not be any uninitialized
+// data in-between fields. Otherwise, the padded data will affect the hmac value and verifications
+// will fail.
+
+void TestVerifiedEventSize() {
+ // VerifiedInputEvent
+ constexpr size_t VERIFIED_INPUT_EVENT_SIZE = sizeof(VerifiedInputEvent::type) +
+ sizeof(VerifiedInputEvent::deviceId) + sizeof(VerifiedInputEvent::eventTimeNanos) +
+ sizeof(VerifiedInputEvent::source) + sizeof(VerifiedInputEvent::displayId);
+ static_assert(sizeof(VerifiedInputEvent) == VERIFIED_INPUT_EVENT_SIZE);
+
+ // VerifiedKeyEvent
+ constexpr size_t VERIFIED_KEY_EVENT_SIZE = VERIFIED_INPUT_EVENT_SIZE +
+ sizeof(VerifiedKeyEvent::action) + sizeof(VerifiedKeyEvent::downTimeNanos) +
+ sizeof(VerifiedKeyEvent::flags) + sizeof(VerifiedKeyEvent::keyCode) +
+ sizeof(VerifiedKeyEvent::scanCode) + sizeof(VerifiedKeyEvent::metaState) +
+ sizeof(VerifiedKeyEvent::repeatCount);
+ static_assert(sizeof(VerifiedKeyEvent) == VERIFIED_KEY_EVENT_SIZE);
+
+ // VerifiedMotionEvent
+ constexpr size_t VERIFIED_MOTION_EVENT_SIZE = VERIFIED_INPUT_EVENT_SIZE +
+ sizeof(VerifiedMotionEvent::rawX) + sizeof(VerifiedMotionEvent::rawY) +
+ sizeof(VerifiedMotionEvent::actionMasked) + sizeof(VerifiedMotionEvent::downTimeNanos) +
+ sizeof(VerifiedMotionEvent::flags) + sizeof(VerifiedMotionEvent::metaState) +
+ sizeof(VerifiedMotionEvent::buttonState);
+ static_assert(sizeof(VerifiedMotionEvent) == VERIFIED_MOTION_EVENT_SIZE);
+}
+
} // namespace android
diff --git a/libs/input/tests/VerifiedInputEvent_test.cpp b/libs/input/tests/VerifiedInputEvent_test.cpp
new file mode 100644
index 0000000..a59dbe5
--- /dev/null
+++ b/libs/input/tests/VerifiedInputEvent_test.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <input/Input.h>
+
+namespace android {
+
+static KeyEvent getKeyEventWithFlags(int32_t flags) {
+ KeyEvent event;
+ event.initialize(2 /*deviceId*/, AINPUT_SOURCE_GAMEPAD, ADISPLAY_ID_DEFAULT, INVALID_HMAC,
+ AKEY_EVENT_ACTION_DOWN, flags, AKEYCODE_BUTTON_X, 121 /*scanCode*/,
+ AMETA_ALT_ON, 1 /*repeatCount*/, 1000 /*downTime*/, 2000 /*eventTime*/);
+ return event;
+}
+
+static MotionEvent getMotionEventWithFlags(int32_t flags) {
+ MotionEvent event;
+ constexpr size_t pointerCount = 1;
+ PointerProperties pointerProperties[pointerCount];
+ PointerCoords pointerCoords[pointerCount];
+ for (size_t i = 0; i < pointerCount; i++) {
+ pointerProperties[i].clear();
+ pointerProperties[i].id = i;
+ pointerCoords[i].clear();
+ }
+
+ event.initialize(0 /*deviceId*/, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_DEFAULT, INVALID_HMAC,
+ AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/, flags,
+ AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/,
+ MotionClassification::NONE, 2 /*xScale*/, 3 /*yScale*/, 4 /*xOffset*/,
+ 5 /*yOffset*/, 0.1 /*xPrecision*/, 0.2 /*yPrecision*/, 280 /*xCursorPosition*/,
+ 540 /*yCursorPosition*/, 100 /*downTime*/, 200 /*eventTime*/, pointerCount,
+ pointerProperties, pointerCoords);
+ return event;
+}
+
+TEST(VerifiedKeyEventTest, ConvertKeyEventToVerifiedKeyEvent) {
+ KeyEvent event = getKeyEventWithFlags(0);
+ VerifiedKeyEvent verified = verifiedKeyEventFromKeyEvent(event);
+
+ ASSERT_EQ(VerifiedInputEvent::Type::KEY, verified.type);
+
+ ASSERT_EQ(event.getDeviceId(), verified.deviceId);
+ ASSERT_EQ(event.getEventTime(), verified.eventTimeNanos);
+ ASSERT_EQ(event.getSource(), verified.source);
+ ASSERT_EQ(event.getDisplayId(), verified.displayId);
+
+ ASSERT_EQ(event.getAction(), verified.action);
+ ASSERT_EQ(event.getDownTime(), verified.downTimeNanos);
+ ASSERT_EQ(event.getFlags() & VERIFIED_KEY_EVENT_FLAGS, verified.flags);
+ ASSERT_EQ(event.getKeyCode(), verified.keyCode);
+ ASSERT_EQ(event.getScanCode(), verified.scanCode);
+ ASSERT_EQ(event.getMetaState(), verified.metaState);
+ ASSERT_EQ(event.getRepeatCount(), verified.repeatCount);
+}
+
+TEST(VerifiedKeyEventTest, VerifiedKeyEventContainsOnlyVerifiedFlags) {
+ KeyEvent event = getKeyEventWithFlags(AKEY_EVENT_FLAG_CANCELED | AKEY_EVENT_FLAG_FALLBACK);
+ VerifiedKeyEvent verified = verifiedKeyEventFromKeyEvent(event);
+ ASSERT_EQ(AKEY_EVENT_FLAG_CANCELED, verified.flags);
+}
+
+TEST(VerifiedKeyEventTest, VerifiedKeyEventDoesNotContainUnverifiedFlags) {
+ KeyEvent event = getKeyEventWithFlags(AKEY_EVENT_FLAG_EDITOR_ACTION);
+ VerifiedKeyEvent verified = verifiedKeyEventFromKeyEvent(event);
+ ASSERT_EQ(0, verified.flags);
+}
+
+TEST(VerifiedMotionEventTest, ConvertMotionEventToVerifiedMotionEvent) {
+ MotionEvent event = getMotionEventWithFlags(0);
+ VerifiedMotionEvent verified = verifiedMotionEventFromMotionEvent(event);
+
+ ASSERT_EQ(VerifiedInputEvent::Type::MOTION, verified.type);
+
+ ASSERT_EQ(event.getDeviceId(), verified.deviceId);
+ ASSERT_EQ(event.getEventTime(), verified.eventTimeNanos);
+ ASSERT_EQ(event.getSource(), verified.source);
+ ASSERT_EQ(event.getDisplayId(), verified.displayId);
+
+ ASSERT_EQ(event.getRawX(0), verified.rawX);
+ ASSERT_EQ(event.getRawY(0), verified.rawY);
+ ASSERT_EQ(event.getAction(), verified.actionMasked);
+ ASSERT_EQ(event.getDownTime(), verified.downTimeNanos);
+ ASSERT_EQ(event.getFlags() & VERIFIED_MOTION_EVENT_FLAGS, verified.flags);
+ ASSERT_EQ(event.getMetaState(), verified.metaState);
+ ASSERT_EQ(event.getButtonState(), verified.buttonState);
+}
+
+TEST(VerifiedMotionEventTest, VerifiedMotionEventContainsOnlyVerifiedFlags) {
+ MotionEvent event = getMotionEventWithFlags(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED |
+ AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE);
+ VerifiedMotionEvent verified = verifiedMotionEventFromMotionEvent(event);
+ ASSERT_EQ(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, verified.flags);
+}
+
+TEST(VerifiedMotionEventTest, VerifiedMotionEventDoesNotContainUnverifiedFlags) {
+ MotionEvent event = getMotionEventWithFlags(AMOTION_EVENT_FLAG_TAINTED);
+ VerifiedMotionEvent verified = verifiedMotionEventFromMotionEvent(event);
+ ASSERT_EQ(0, verified.flags);
+}
+
+} // namespace android
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index a1c9eb8..98b76fd 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -165,6 +165,14 @@
return native_window_set_frame_rate(window, frameRate);
}
+void ANativeWindow_tryAllocateBuffers(ANativeWindow* window) {
+ if (!window || !query(window, NATIVE_WINDOW_IS_VALID)) {
+ return;
+ }
+ window->perform(window, NATIVE_WINDOW_ALLOCATE_BUFFERS);
+}
+
+
/**************************************************************************************************
* vndk-stable
**************************************************************************************************/
@@ -328,10 +336,6 @@
return window->perform(window, NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR, interceptor, data);
}
-void ANativeWindow_allocateBuffers(ANativeWindow* window) {
- window->perform(window, NATIVE_WINDOW_ALLOCATE_BUFFERS);
-}
-
int64_t ANativeWindow_getNextFrameId(ANativeWindow* window) {
return query64(window, NATIVE_WINDOW_GET_NEXT_FRAME_ID);
}
diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index 262aee3..4b426c5 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -261,6 +261,17 @@
*/
int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate) __INTRODUCED_IN(30);
+/**
+ * Provides a hint to the window that buffers should be preallocated ahead of
+ * time. Note that the window implementation is not guaranteed to preallocate
+ * any buffers, for instance if an implementation disallows allocation of new
+ * buffers, or if there is insufficient memory in the system to preallocate
+ * additional buffers
+ *
+ * Available since API level 30.
+ */
+void ANativeWindow_tryAllocateBuffers(ANativeWindow* window);
+
#endif // __ANDROID_API__ >= 30
#ifdef __cplusplus
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 121374b..f686147 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -253,6 +253,7 @@
NATIVE_WINDOW_SET_PERFORM_INTERCEPTOR = 43, /* private */
NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR = 44, /* private */
NATIVE_WINDOW_ALLOCATE_BUFFERS = 45, /* private */
+ NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER = 46, /* private */
// clang-format on
};
@@ -1018,4 +1019,34 @@
return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, (double)frameRate);
}
+// ------------------------------------------------------------------------------------------------
+// Candidates for APEX visibility
+// These functions are planned to be made stable for APEX modules, but have not
+// yet been stabilized to a specific api version.
+// ------------------------------------------------------------------------------------------------
+
+/**
+ * Retrieves the last queued buffer for this window, along with the fence that
+ * fires when the buffer is ready to be read, and the 4x4 coordinate
+ * transform matrix that should be applied to the buffer's content. The
+ * transform matrix is represented in column-major order.
+ *
+ * If there was no buffer previously queued, then outBuffer will be NULL and
+ * the value of outFence will be -1.
+ *
+ * Note that if outBuffer is not NULL, then the caller will hold a reference
+ * onto the buffer. Accordingly, the caller must call AHardwareBuffer_release
+ * when the buffer is no longer needed so that the system may reclaim the
+ * buffer.
+ *
+ * \return NO_ERROR on success.
+ * \return NO_MEMORY if there was insufficient memory.
+ */
+static inline int ANativeWindow_getLastQueuedBuffer(ANativeWindow* window,
+ AHardwareBuffer** outBuffer, int* outFence,
+ float outTransformMatrix[16]) {
+ return window->perform(window, NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER, outBuffer, outFence,
+ outTransformMatrix);
+}
+
__END_DECLS
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index e0e20c3..154eb8e 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -17,7 +17,6 @@
ANativeWindow_OemStorageGet; # llndk
ANativeWindow_OemStorageSet; # llndk
ANativeWindow_acquire;
- ANativeWindow_allocateBuffers; # apex # introduced=30
ANativeWindow_cancelBuffer; # llndk
ANativeWindow_dequeueBuffer; # llndk
ANativeWindow_getBuffersDataSpace; # introduced=28
@@ -51,6 +50,7 @@
ANativeWindow_setSwapInterval; # llndk
ANativeWindow_setFrameRate; # introduced=30
ANativeWindow_setUsage; # llndk
+ ANativeWindow_tryAllocateBuffers; # introduced=30
ANativeWindow_unlockAndPost;
local:
*;
diff --git a/libs/ui/include/ui/DisplayInfo.h b/libs/ui/include/ui/DisplayInfo.h
index 7773319..69f86d3 100644
--- a/libs/ui/include/ui/DisplayInfo.h
+++ b/libs/ui/include/ui/DisplayInfo.h
@@ -20,8 +20,11 @@
namespace android {
+enum class DisplayConnectionType { Internal, External };
+
// Immutable information about physical display.
struct DisplayInfo {
+ DisplayConnectionType connectionType = DisplayConnectionType::Internal;
float density = 0.f;
bool secure = false;
};
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 308e93a..5c80d55 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -40,6 +40,7 @@
"libinputreporter",
"libinputreader",
"libbinder",
+ "libcrypto",
"libcutils",
"libhidlbase",
"libinput",
diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp
index a556aad..3f956a8 100644
--- a/services/inputflinger/dispatcher/Android.bp
+++ b/services/inputflinger/dispatcher/Android.bp
@@ -28,6 +28,7 @@
],
shared_libs: [
"libbase",
+ "libcrypto",
"libcutils",
"libinput",
"libinputreporter",
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index f2b95e7..75bc0aa 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -60,7 +60,10 @@
#include <android-base/chrono_utils.h>
#include <android-base/stringprintf.h>
#include <binder/Binder.h>
+#include <input/InputDevice.h>
#include <log/log.h>
+#include <openssl/hmac.h>
+#include <openssl/rand.h>
#include <powermanager/PowerManager.h>
#include <utils/Trace.h>
@@ -325,6 +328,55 @@
return dispatchEntry;
}
+static std::array<uint8_t, 128> getRandomKey() {
+ std::array<uint8_t, 128> key;
+ if (RAND_bytes(key.data(), key.size()) != 1) {
+ LOG_ALWAYS_FATAL("Can't generate HMAC key");
+ }
+ return key;
+}
+
+// --- HmacKeyManager ---
+
+HmacKeyManager::HmacKeyManager() : mHmacKey(getRandomKey()) {}
+
+std::array<uint8_t, 32> HmacKeyManager::sign(const VerifiedInputEvent& event) const {
+ size_t size;
+ switch (event.type) {
+ case VerifiedInputEvent::Type::KEY: {
+ size = sizeof(VerifiedKeyEvent);
+ break;
+ }
+ case VerifiedInputEvent::Type::MOTION: {
+ size = sizeof(VerifiedMotionEvent);
+ break;
+ }
+ }
+ std::vector<uint8_t> data;
+ const uint8_t* start = reinterpret_cast<const uint8_t*>(&event);
+ data.assign(start, start + size);
+ return sign(data);
+}
+
+std::array<uint8_t, 32> HmacKeyManager::sign(const std::vector<uint8_t>& data) const {
+ // SHA256 always generates 32-bytes result
+ std::array<uint8_t, 32> hash;
+ unsigned int hashLen = 0;
+ uint8_t* result = HMAC(EVP_sha256(), mHmacKey.data(), mHmacKey.size(), data.data(), data.size(),
+ hash.data(), &hashLen);
+ if (result == nullptr) {
+ ALOGE("Could not sign the data using HMAC");
+ return INVALID_HMAC;
+ }
+
+ if (hashLen != hash.size()) {
+ ALOGE("HMAC-SHA256 has unexpected length");
+ return INVALID_HMAC;
+ }
+
+ return hash;
+}
+
// --- InputDispatcher ---
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy)
@@ -3153,22 +3205,22 @@
std::queue<EventEntry*> injectedEntries;
switch (event->getType()) {
case AINPUT_EVENT_TYPE_KEY: {
- KeyEvent keyEvent;
- keyEvent.initialize(*static_cast<const KeyEvent*>(event));
- int32_t action = keyEvent.getAction();
+ const KeyEvent& incomingKey = static_cast<const KeyEvent&>(*event);
+ int32_t action = incomingKey.getAction();
if (!validateKeyEvent(action)) {
return INPUT_EVENT_INJECTION_FAILED;
}
- int32_t flags = keyEvent.getFlags();
- int32_t keyCode = keyEvent.getKeyCode();
- int32_t metaState = keyEvent.getMetaState();
- accelerateMetaShortcuts(keyEvent.getDeviceId(), action,
+ int32_t flags = incomingKey.getFlags();
+ int32_t keyCode = incomingKey.getKeyCode();
+ int32_t metaState = incomingKey.getMetaState();
+ accelerateMetaShortcuts(VIRTUAL_KEYBOARD_ID, action,
/*byref*/ keyCode, /*byref*/ metaState);
- keyEvent.initialize(keyEvent.getDeviceId(), keyEvent.getSource(),
- keyEvent.getDisplayId(), INVALID_HMAC, action, flags, keyCode,
- keyEvent.getScanCode(), metaState, keyEvent.getRepeatCount(),
- keyEvent.getDownTime(), keyEvent.getEventTime());
+ KeyEvent keyEvent;
+ keyEvent.initialize(VIRTUAL_KEYBOARD_ID, incomingKey.getSource(),
+ incomingKey.getDisplayId(), INVALID_HMAC, action, flags, keyCode,
+ incomingKey.getScanCode(), metaState, incomingKey.getRepeatCount(),
+ incomingKey.getDownTime(), incomingKey.getEventTime());
if (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY) {
policyFlags |= POLICY_FLAG_VIRTUAL;
@@ -3186,11 +3238,10 @@
mLock.lock();
KeyEntry* injectedEntry =
new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, keyEvent.getEventTime(),
- keyEvent.getDeviceId(), keyEvent.getSource(),
- keyEvent.getDisplayId(), policyFlags, action, flags,
- keyEvent.getKeyCode(), keyEvent.getScanCode(),
- keyEvent.getMetaState(), keyEvent.getRepeatCount(),
- keyEvent.getDownTime());
+ VIRTUAL_KEYBOARD_ID, keyEvent.getSource(), keyEvent.getDisplayId(),
+ policyFlags, action, flags, keyEvent.getKeyCode(),
+ keyEvent.getScanCode(), keyEvent.getMetaState(),
+ keyEvent.getRepeatCount(), keyEvent.getDownTime());
injectedEntries.push(injectedEntry);
break;
}
@@ -3221,7 +3272,7 @@
const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords();
MotionEntry* injectedEntry =
new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes,
- motionEvent->getDeviceId(), motionEvent->getSource(),
+ VIRTUAL_KEYBOARD_ID, motionEvent->getSource(),
motionEvent->getDisplayId(), policyFlags, action, actionButton,
motionEvent->getFlags(), motionEvent->getMetaState(),
motionEvent->getButtonState(), motionEvent->getClassification(),
@@ -3238,7 +3289,7 @@
samplePointerCoords += pointerCount;
MotionEntry* nextInjectedEntry =
new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes,
- motionEvent->getDeviceId(), motionEvent->getSource(),
+ VIRTUAL_KEYBOARD_ID, motionEvent->getSource(),
motionEvent->getDisplayId(), policyFlags, action,
actionButton, motionEvent->getFlags(),
motionEvent->getMetaState(), motionEvent->getButtonState(),
@@ -3340,6 +3391,10 @@
return injectionResult;
}
+std::unique_ptr<VerifiedInputEvent> InputDispatcher::verifyInputEvent(const InputEvent& event) {
+ return nullptr;
+}
+
bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) {
return injectorUid == 0 ||
mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid);
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index d2aea80..ded59a5 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -56,6 +56,16 @@
class Connection;
+class HmacKeyManager {
+public:
+ HmacKeyManager();
+ std::array<uint8_t, 32> sign(const VerifiedInputEvent& event) const;
+
+private:
+ std::array<uint8_t, 32> sign(const std::vector<uint8_t>& data) const;
+ const std::array<uint8_t, 128> mHmacKey;
+};
+
/* Dispatches events to input targets. Some functions of the input dispatcher, such as
* identifying input targets, are controlled by a separate policy object.
*
@@ -96,6 +106,8 @@
int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
uint32_t policyFlags) override;
+ virtual std::unique_ptr<VerifiedInputEvent> verifyInputEvent(const InputEvent& event) override;
+
virtual void setInputWindows(
const std::vector<sp<InputWindowHandle>>& inputWindowHandles, int32_t displayId,
const sp<ISetInputWindowsListener>& setInputWindowsListener = nullptr) override;
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index 3424f4c..6e98676 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -92,6 +92,13 @@
int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
uint32_t policyFlags) = 0;
+ /*
+ * Check whether InputEvent actually happened by checking the signature of the event.
+ *
+ * Return nullptr if the event cannot be verified.
+ */
+ virtual std::unique_ptr<VerifiedInputEvent> verifyInputEvent(const InputEvent& event) = 0;
+
/* Sets the list of input windows.
*
* This method may be called on any thread (usually by the input manager).
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index 7fed61f..1c08ab1 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -18,7 +18,16 @@
#include "InputDevice.h"
-#include "InputMapper.h"
+#include "CursorInputMapper.h"
+#include "ExternalStylusInputMapper.h"
+#include "InputReaderContext.h"
+#include "JoystickInputMapper.h"
+#include "KeyboardInputMapper.h"
+#include "MultiTouchInputMapper.h"
+#include "RotaryEncoderInputMapper.h"
+#include "SingleTouchInputMapper.h"
+#include "SwitchInputMapper.h"
+#include "VibratorInputMapper.h"
namespace android {
@@ -36,13 +45,7 @@
mHasMic(false),
mDropUntilNextSync(false) {}
-InputDevice::~InputDevice() {
- size_t numMappers = mMappers.size();
- for (size_t i = 0; i < numMappers; i++) {
- delete mMappers[i];
- }
- mMappers.clear();
-}
+InputDevice::~InputDevice() {}
bool InputDevice::isEnabled() {
return getEventHub()->isDeviceEnabled(mId);
@@ -110,15 +113,80 @@
}
}
- size_t numMappers = mMappers.size();
- for (size_t i = 0; i < numMappers; i++) {
- InputMapper* mapper = mMappers[i];
- mapper->dump(dump);
- }
+ for_each_mapper([&dump](InputMapper& mapper) { mapper.dump(dump); });
}
-void InputDevice::addMapper(InputMapper* mapper) {
- mMappers.push_back(mapper);
+void InputDevice::populateMappers() {
+ uint32_t classes = mClasses;
+ std::vector<std::unique_ptr<InputMapper>>& mappers = mMappers;
+
+ // External devices.
+ if (classes & INPUT_DEVICE_CLASS_EXTERNAL) {
+ setExternal(true);
+ }
+
+ // Devices with mics.
+ if (classes & INPUT_DEVICE_CLASS_MIC) {
+ setMic(true);
+ }
+
+ // Switch-like devices.
+ if (classes & INPUT_DEVICE_CLASS_SWITCH) {
+ mappers.push_back(std::make_unique<SwitchInputMapper>(this));
+ }
+
+ // Scroll wheel-like devices.
+ if (classes & INPUT_DEVICE_CLASS_ROTARY_ENCODER) {
+ mappers.push_back(std::make_unique<RotaryEncoderInputMapper>(this));
+ }
+
+ // Vibrator-like devices.
+ if (classes & INPUT_DEVICE_CLASS_VIBRATOR) {
+ mappers.push_back(std::make_unique<VibratorInputMapper>(this));
+ }
+
+ // Keyboard-like devices.
+ uint32_t keyboardSource = 0;
+ int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;
+ if (classes & INPUT_DEVICE_CLASS_KEYBOARD) {
+ keyboardSource |= AINPUT_SOURCE_KEYBOARD;
+ }
+ if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) {
+ keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;
+ }
+ if (classes & INPUT_DEVICE_CLASS_DPAD) {
+ keyboardSource |= AINPUT_SOURCE_DPAD;
+ }
+ if (classes & INPUT_DEVICE_CLASS_GAMEPAD) {
+ keyboardSource |= AINPUT_SOURCE_GAMEPAD;
+ }
+
+ if (keyboardSource != 0) {
+ mappers.push_back(
+ std::make_unique<KeyboardInputMapper>(this, keyboardSource, keyboardType));
+ }
+
+ // Cursor-like devices.
+ if (classes & INPUT_DEVICE_CLASS_CURSOR) {
+ mappers.push_back(std::make_unique<CursorInputMapper>(this));
+ }
+
+ // Touchscreens and touchpad devices.
+ if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
+ mappers.push_back(std::make_unique<MultiTouchInputMapper>(this));
+ } else if (classes & INPUT_DEVICE_CLASS_TOUCH) {
+ mappers.push_back(std::make_unique<SingleTouchInputMapper>(this));
+ }
+
+ // Joystick-like devices.
+ if (classes & INPUT_DEVICE_CLASS_JOYSTICK) {
+ mappers.push_back(std::make_unique<JoystickInputMapper>(this));
+ }
+
+ // External stylus-like devices.
+ if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
+ mappers.push_back(std::make_unique<ExternalStylusInputMapper>(this));
+ }
}
void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config,
@@ -193,10 +261,10 @@
}
}
- for (InputMapper* mapper : mMappers) {
- mapper->configure(when, config, changes);
- mSources |= mapper->getSources();
- }
+ for_each_mapper([this, when, config, changes](InputMapper& mapper) {
+ mapper.configure(when, config, changes);
+ mSources |= mapper.getSources();
+ });
// If a device is just plugged but it might be disabled, we need to update some info like
// axis range of touch from each InputMapper first, then disable it.
@@ -207,9 +275,7 @@
}
void InputDevice::reset(nsecs_t when) {
- for (InputMapper* mapper : mMappers) {
- mapper->reset(when);
- }
+ for_each_mapper([when](InputMapper& mapper) { mapper.reset(when); });
mContext->updateGlobalMetaState();
@@ -244,32 +310,25 @@
mDropUntilNextSync = true;
reset(rawEvent->when);
} else {
- for (InputMapper* mapper : mMappers) {
- mapper->process(rawEvent);
- }
+ for_each_mapper([rawEvent](InputMapper& mapper) { mapper.process(rawEvent); });
}
--count;
}
}
void InputDevice::timeoutExpired(nsecs_t when) {
- for (InputMapper* mapper : mMappers) {
- mapper->timeoutExpired(when);
- }
+ for_each_mapper([when](InputMapper& mapper) { mapper.timeoutExpired(when); });
}
void InputDevice::updateExternalStylusState(const StylusState& state) {
- for (InputMapper* mapper : mMappers) {
- mapper->updateExternalStylusState(state);
- }
+ for_each_mapper([state](InputMapper& mapper) { mapper.updateExternalStylusState(state); });
}
void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) {
outDeviceInfo->initialize(mId, mGeneration, mControllerNumber, mIdentifier, mAlias, mIsExternal,
mHasMic);
- for (InputMapper* mapper : mMappers) {
- mapper->populateDeviceInfo(outDeviceInfo);
- }
+ for_each_mapper(
+ [outDeviceInfo](InputMapper& mapper) { mapper.populateDeviceInfo(outDeviceInfo); });
}
int32_t InputDevice::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
@@ -286,11 +345,12 @@
int32_t InputDevice::getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc) {
int32_t result = AKEY_STATE_UNKNOWN;
- for (InputMapper* mapper : mMappers) {
- if (sourcesMatchMask(mapper->getSources(), sourceMask)) {
+ for (auto& mapperPtr : mMappers) {
+ InputMapper& mapper = *mapperPtr;
+ if (sourcesMatchMask(mapper.getSources(), sourceMask)) {
// If any mapper reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that
// value. Otherwise, return AKEY_STATE_UP as long as one mapper reports it.
- int32_t currentResult = (mapper->*getStateFunc)(sourceMask, code);
+ int32_t currentResult = (mapper.*getStateFunc)(sourceMask, code);
if (currentResult >= AKEY_STATE_DOWN) {
return currentResult;
} else if (currentResult == AKEY_STATE_UP) {
@@ -304,51 +364,41 @@
bool InputDevice::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
const int32_t* keyCodes, uint8_t* outFlags) {
bool result = false;
- for (InputMapper* mapper : mMappers) {
- if (sourcesMatchMask(mapper->getSources(), sourceMask)) {
- result |= mapper->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags);
+ for_each_mapper([&result, sourceMask, numCodes, keyCodes, outFlags](InputMapper& mapper) {
+ if (sourcesMatchMask(mapper.getSources(), sourceMask)) {
+ result |= mapper.markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags);
}
- }
+ });
return result;
}
void InputDevice::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
int32_t token) {
- for (InputMapper* mapper : mMappers) {
- mapper->vibrate(pattern, patternSize, repeat, token);
- }
+ for_each_mapper([pattern, patternSize, repeat, token](InputMapper& mapper) {
+ mapper.vibrate(pattern, patternSize, repeat, token);
+ });
}
void InputDevice::cancelVibrate(int32_t token) {
- for (InputMapper* mapper : mMappers) {
- mapper->cancelVibrate(token);
- }
+ for_each_mapper([token](InputMapper& mapper) { mapper.cancelVibrate(token); });
}
void InputDevice::cancelTouch(nsecs_t when) {
- for (InputMapper* mapper : mMappers) {
- mapper->cancelTouch(when);
- }
+ for_each_mapper([when](InputMapper& mapper) { mapper.cancelTouch(when); });
}
int32_t InputDevice::getMetaState() {
int32_t result = 0;
- for (InputMapper* mapper : mMappers) {
- result |= mapper->getMetaState();
- }
+ for_each_mapper([&result](InputMapper& mapper) { result |= mapper.getMetaState(); });
return result;
}
void InputDevice::updateMetaState(int32_t keyCode) {
- for (InputMapper* mapper : mMappers) {
- mapper->updateMetaState(keyCode);
- }
+ for_each_mapper([keyCode](InputMapper& mapper) { mapper.updateMetaState(keyCode); });
}
void InputDevice::fadePointer() {
- for (InputMapper* mapper : mMappers) {
- mapper->fadePointer();
- }
+ for_each_mapper([](InputMapper& mapper) { mapper.fadePointer(); });
}
void InputDevice::bumpGeneration() {
@@ -367,14 +417,8 @@
}
// No associated display port, check if some InputMapper is associated.
- for (InputMapper* mapper : mMappers) {
- std::optional<int32_t> associatedDisplayId = mapper->getAssociatedDisplayId();
- if (associatedDisplayId) {
- return associatedDisplayId;
- }
- }
-
- return std::nullopt;
+ return first_in_mappers<int32_t>(
+ [](InputMapper& mapper) { return mapper.getAssociatedDisplayId(); });
}
} // namespace android
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 2023c6e..010729a 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -18,33 +18,22 @@
#include "InputReader.h"
-#include "CursorInputMapper.h"
-#include "ExternalStylusInputMapper.h"
-#include "InputReaderContext.h"
-#include "JoystickInputMapper.h"
-#include "KeyboardInputMapper.h"
-#include "MultiTouchInputMapper.h"
-#include "RotaryEncoderInputMapper.h"
-#include "SingleTouchInputMapper.h"
-#include "SwitchInputMapper.h"
-#include "VibratorInputMapper.h"
-
+#include <android-base/stringprintf.h>
#include <errno.h>
+#include <input/Keyboard.h>
+#include <input/VirtualKeyMap.h>
#include <inttypes.h>
#include <limits.h>
+#include <log/log.h>
#include <math.h>
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
-
-#include <log/log.h>
#include <utils/Errors.h>
-
-#include <android-base/stringprintf.h>
-#include <input/Keyboard.h>
-#include <input/VirtualKeyMap.h>
#include <utils/Thread.h>
+#include "InputDevice.h"
+
using android::base::StringPrintf;
namespace android {
@@ -261,74 +250,7 @@
uint32_t classes) {
InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(),
controllerNumber, identifier, classes);
-
- // External devices.
- if (classes & INPUT_DEVICE_CLASS_EXTERNAL) {
- device->setExternal(true);
- }
-
- // Devices with mics.
- if (classes & INPUT_DEVICE_CLASS_MIC) {
- device->setMic(true);
- }
-
- // Switch-like devices.
- if (classes & INPUT_DEVICE_CLASS_SWITCH) {
- device->addMapper(new SwitchInputMapper(device));
- }
-
- // Scroll wheel-like devices.
- if (classes & INPUT_DEVICE_CLASS_ROTARY_ENCODER) {
- device->addMapper(new RotaryEncoderInputMapper(device));
- }
-
- // Vibrator-like devices.
- if (classes & INPUT_DEVICE_CLASS_VIBRATOR) {
- device->addMapper(new VibratorInputMapper(device));
- }
-
- // Keyboard-like devices.
- uint32_t keyboardSource = 0;
- int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;
- if (classes & INPUT_DEVICE_CLASS_KEYBOARD) {
- keyboardSource |= AINPUT_SOURCE_KEYBOARD;
- }
- if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) {
- keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;
- }
- if (classes & INPUT_DEVICE_CLASS_DPAD) {
- keyboardSource |= AINPUT_SOURCE_DPAD;
- }
- if (classes & INPUT_DEVICE_CLASS_GAMEPAD) {
- keyboardSource |= AINPUT_SOURCE_GAMEPAD;
- }
-
- if (keyboardSource != 0) {
- device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType));
- }
-
- // Cursor-like devices.
- if (classes & INPUT_DEVICE_CLASS_CURSOR) {
- device->addMapper(new CursorInputMapper(device));
- }
-
- // Touchscreens and touchpad devices.
- if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
- device->addMapper(new MultiTouchInputMapper(device));
- } else if (classes & INPUT_DEVICE_CLASS_TOUCH) {
- device->addMapper(new SingleTouchInputMapper(device));
- }
-
- // Joystick-like devices.
- if (classes & INPUT_DEVICE_CLASS_JOYSTICK) {
- device->addMapper(new JoystickInputMapper(device));
- }
-
- // External stylus-like devices.
- if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
- device->addMapper(new ExternalStylusInputMapper(device));
- }
-
+ device->populateMappers();
return device;
}
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index 882407d..d06cc20 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -67,7 +67,7 @@
void setEnabled(bool enabled, nsecs_t when);
void dump(std::string& dump);
- void addMapper(InputMapper* mapper);
+ void populateMappers();
void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
void reset(nsecs_t when);
void process(const RawEvent* rawEvents, size_t count);
@@ -116,6 +116,14 @@
std::optional<int32_t> getAssociatedDisplayId();
+ // construct and add a mapper to the input device
+ template <class T, typename... Args>
+ T& addMapper(Args... args) {
+ T* mapper = new T(this, args...);
+ mMappers.emplace_back(mapper);
+ return *mapper;
+ }
+
private:
InputReaderContext* mContext;
int32_t mId;
@@ -125,7 +133,7 @@
std::string mAlias;
uint32_t mClasses;
- std::vector<InputMapper*> mMappers;
+ std::vector<std::unique_ptr<InputMapper>> mMappers;
uint32_t mSources;
bool mIsExternal;
@@ -138,6 +146,26 @@
int32_t getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc);
PropertyMap mConfiguration;
+
+ // run a function against every mapper
+ inline void for_each_mapper(std::function<void(InputMapper&)> f) {
+ for (auto& mapperPtr : mMappers) {
+ f(*mapperPtr);
+ }
+ }
+
+ // return the first value returned by a function over every mapper.
+ // if all mappers return nullopt, return nullopt.
+ template <typename T>
+ inline std::optional<T> first_in_mappers(std::function<std::optional<T>(InputMapper&)> f) {
+ for (auto& mapperPtr : mMappers) {
+ std::optional<T> ret = f(*mapperPtr);
+ if (ret) {
+ return ret;
+ }
+ }
+ return std::nullopt;
+ }
};
} // namespace android
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 09ecb13..f913d82 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -10,6 +10,7 @@
"InputClassifierConverter_test.cpp",
"InputDispatcher_test.cpp",
"InputReader_test.cpp",
+ "UinputDevice.cpp",
],
cflags: [
"-Wall",
diff --git a/services/inputflinger/tests/EventHub_test.cpp b/services/inputflinger/tests/EventHub_test.cpp
index 6504738..be2e19e 100644
--- a/services/inputflinger/tests/EventHub_test.cpp
+++ b/services/inputflinger/tests/EventHub_test.cpp
@@ -16,7 +16,8 @@
#include "EventHub.h"
-#include <android-base/stringprintf.h>
+#include "UinputDevice.h"
+
#include <gtest/gtest.h>
#include <inttypes.h>
#include <linux/uinput.h>
@@ -25,16 +26,16 @@
#define TAG "EventHub_test"
+using android::createUinputDevice;
using android::EventHub;
using android::EventHubInterface;
using android::InputDeviceIdentifier;
using android::RawEvent;
using android::sp;
-using android::base::StringPrintf;
+using android::UinputHomeKey;
using std::chrono_literals::operator""ms;
static constexpr bool DEBUG = false;
-static const char* DEVICE_NAME = "EventHub Test Device";
static void dumpEvents(const std::vector<RawEvent>& events) {
for (const RawEvent& event : events) {
@@ -62,27 +63,26 @@
protected:
std::unique_ptr<EventHubInterface> mEventHub;
// We are only going to emulate a single input device currently.
- android::base::unique_fd mDeviceFd;
+ std::unique_ptr<UinputHomeKey> mKeyboard;
int32_t mDeviceId;
+
virtual void SetUp() override {
mEventHub = std::make_unique<EventHub>();
consumeInitialDeviceAddedEvents();
- createDevice();
+ mKeyboard = createUinputDevice<UinputHomeKey>();
mDeviceId = waitForDeviceCreation();
}
virtual void TearDown() override {
- mDeviceFd.reset();
+ mKeyboard.reset();
waitForDeviceClose(mDeviceId);
}
- void createDevice();
/**
* Return the device id of the created device.
*/
int32_t waitForDeviceCreation();
void waitForDeviceClose(int32_t deviceId);
void consumeInitialDeviceAddedEvents();
- void sendEvent(uint16_t type, uint16_t code, int32_t value);
std::vector<RawEvent> getEvents(std::chrono::milliseconds timeout = 5ms);
};
@@ -105,48 +105,6 @@
return events;
}
-void EventHubTest::createDevice() {
- mDeviceFd = android::base::unique_fd(open("/dev/uinput", O_WRONLY | O_NONBLOCK));
- if (mDeviceFd < 0) {
- FAIL() << "Can't open /dev/uinput :" << strerror(errno);
- }
-
- /**
- * Signal which type of events this input device supports.
- * We will emulate a keyboard here.
- */
- // enable key press/release event
- if (ioctl(mDeviceFd, UI_SET_EVBIT, EV_KEY)) {
- ADD_FAILURE() << "Error in ioctl : UI_SET_EVBIT : EV_KEY: " << strerror(errno);
- }
-
- // enable set of KEY events
- if (ioctl(mDeviceFd, UI_SET_KEYBIT, KEY_HOME)) {
- ADD_FAILURE() << "Error in ioctl : UI_SET_KEYBIT : KEY_HOME: " << strerror(errno);
- }
-
- // enable synchronization event
- if (ioctl(mDeviceFd, UI_SET_EVBIT, EV_SYN)) {
- ADD_FAILURE() << "Error in ioctl : UI_SET_EVBIT : EV_SYN: " << strerror(errno);
- }
-
- struct uinput_user_dev keyboard = {};
- strlcpy(keyboard.name, DEVICE_NAME, UINPUT_MAX_NAME_SIZE);
- keyboard.id.bustype = BUS_USB;
- keyboard.id.vendor = 0x01;
- keyboard.id.product = 0x01;
- keyboard.id.version = 1;
-
- if (write(mDeviceFd, &keyboard, sizeof(keyboard)) < 0) {
- FAIL() << "Could not write uinput_user_dev struct into uinput file descriptor: "
- << strerror(errno);
- }
-
- if (ioctl(mDeviceFd, UI_DEV_CREATE)) {
- FAIL() << "Error in ioctl : UI_DEV_CREATE: " << strerror(errno);
- }
-}
-
/**
* Since the test runs on a real platform, there will be existing devices
* in addition to the test devices being added. Therefore, when EventHub is first created,
@@ -176,7 +134,7 @@
EXPECT_EQ(static_cast<int32_t>(EventHubInterface::DEVICE_ADDED), deviceAddedEvent.type);
InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceAddedEvent.deviceId);
const int32_t deviceId = deviceAddedEvent.deviceId;
- EXPECT_EQ(identifier.name, DEVICE_NAME);
+ EXPECT_EQ(identifier.name, mKeyboard->getName());
const RawEvent& finishedDeviceScanEvent = events[1];
EXPECT_EQ(static_cast<int32_t>(EventHubInterface::FINISHED_DEVICE_SCAN),
finishedDeviceScanEvent.type);
@@ -194,22 +152,6 @@
finishedDeviceScanEvent.type);
}
-void EventHubTest::sendEvent(uint16_t type, uint16_t code, int32_t value) {
- struct input_event event = {};
- event.type = type;
- event.code = code;
- event.value = value;
- event.time = {}; // uinput ignores the timestamp
-
- if (write(mDeviceFd, &event, sizeof(input_event)) < 0) {
- std::string msg = StringPrintf("Could not write event %" PRIu16 " %" PRIu16
- " with value %" PRId32 " : %s",
- type, code, value, strerror(errno));
- ALOGE("%s", msg.c_str());
- ADD_FAILURE() << msg.c_str();
- }
-}
-
/**
* Ensure that input_events are generated with monotonic clock.
* That means input_event should receive a timestamp that is in the future of the time
@@ -218,13 +160,7 @@
*/
TEST_F(EventHubTest, InputEvent_TimestampIsMonotonic) {
nsecs_t lastEventTime = systemTime(SYSTEM_TIME_MONOTONIC);
- // key press
- sendEvent(EV_KEY, KEY_HOME, 1);
- sendEvent(EV_SYN, SYN_REPORT, 0);
-
- // key release
- sendEvent(EV_KEY, KEY_HOME, 0);
- sendEvent(EV_SYN, SYN_REPORT, 0);
+ ASSERT_NO_FATAL_FAILURE(mKeyboard->pressAndReleaseHomeKey());
std::vector<RawEvent> events = getEvents();
ASSERT_EQ(4U, events.size()) << "Expected to receive 2 keys and 2 syncs, total of 4 events";
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 27db8f5..c4092cd 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -43,6 +43,18 @@
float y;
};
+/**
+ * Return a DOWN key event with KEYCODE_A.
+ */
+static KeyEvent getTestKeyEvent() {
+ KeyEvent event;
+
+ event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, INVALID_HMAC,
+ AKEY_EVENT_ACTION_DOWN, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME,
+ ARBITRARY_TIME);
+ return event;
+}
+
// --- FakeInputDispatcherPolicy ---
class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface {
@@ -197,6 +209,69 @@
}
};
+// --- HmacKeyManagerTest ---
+
+class HmacKeyManagerTest : public testing::Test {
+protected:
+ HmacKeyManager mHmacKeyManager;
+};
+
+/**
+ * Ensure that separate calls to sign the same data are generating the same key.
+ * We avoid asserting against INVALID_HMAC. Since the key is random, there is a non-zero chance
+ * that a specific key and data combination would produce INVALID_HMAC, which would cause flaky
+ * tests.
+ */
+TEST_F(HmacKeyManagerTest, GeneratedHmac_IsConsistent) {
+ KeyEvent event = getTestKeyEvent();
+ VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event);
+
+ std::array<uint8_t, 32> hmac1 = mHmacKeyManager.sign(verifiedEvent);
+ std::array<uint8_t, 32> hmac2 = mHmacKeyManager.sign(verifiedEvent);
+ ASSERT_EQ(hmac1, hmac2);
+}
+
+/**
+ * Ensure that changes in VerifiedKeyEvent produce a different hmac.
+ */
+TEST_F(HmacKeyManagerTest, GeneratedHmac_ChangesWhenFieldsChange) {
+ KeyEvent event = getTestKeyEvent();
+ VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event);
+ std::array<uint8_t, 32> initialHmac = mHmacKeyManager.sign(verifiedEvent);
+
+ verifiedEvent.deviceId += 1;
+ ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+
+ verifiedEvent.source += 1;
+ ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+
+ verifiedEvent.eventTimeNanos += 1;
+ ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+
+ verifiedEvent.displayId += 1;
+ ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+
+ verifiedEvent.action += 1;
+ ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+
+ verifiedEvent.downTimeNanos += 1;
+ ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+
+ verifiedEvent.flags += 1;
+ ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+
+ verifiedEvent.keyCode += 1;
+ ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+
+ verifiedEvent.scanCode += 1;
+ ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+
+ verifiedEvent.metaState += 1;
+ ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+
+ verifiedEvent.repeatCount += 1;
+ ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+}
// --- InputDispatcherTest ---
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 8ca7e4a..7cd8793 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -1354,22 +1354,22 @@
ASSERT_NO_FATAL_FAILURE(mFakeEventHub->assertQueueIsEmpty());
}
- void disableDevice(int32_t deviceId, InputDevice* device) {
+ void disableDevice(int32_t deviceId) {
mFakePolicy->addDisabledDevice(deviceId);
mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_ENABLED_STATE);
}
- void enableDevice(int32_t deviceId, InputDevice* device) {
+ void enableDevice(int32_t deviceId) {
mFakePolicy->removeDisabledDevice(deviceId);
mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_ENABLED_STATE);
}
- FakeInputMapper* addDeviceWithFakeInputMapper(int32_t deviceId, int32_t controllerNumber,
- const std::string& name, uint32_t classes, uint32_t sources,
- const PropertyMap* configuration) {
+ FakeInputMapper& addDeviceWithFakeInputMapper(int32_t deviceId, int32_t controllerNumber,
+ const std::string& name, uint32_t classes,
+ uint32_t sources,
+ const PropertyMap* configuration) {
InputDevice* device = mReader->newDevice(deviceId, controllerNumber, name, classes);
- FakeInputMapper* mapper = new FakeInputMapper(device, sources);
- device->addMapper(mapper);
+ FakeInputMapper& mapper = device->addMapper<FakeInputMapper>(sources);
mReader->setNextDevice(device);
addDevice(deviceId, name, classes, configuration);
return mapper;
@@ -1406,8 +1406,7 @@
constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD;
InputDevice* device = mReader->newDevice(deviceId, 0 /*controllerNumber*/, "fake", deviceClass);
// Must add at least one mapper or the device will be ignored!
- FakeInputMapper* mapper = new FakeInputMapper(device, AINPUT_SOURCE_KEYBOARD);
- device->addMapper(mapper);
+ device->addMapper<FakeInputMapper>(AINPUT_SOURCE_KEYBOARD);
mReader->setNextDevice(device);
ASSERT_NO_FATAL_FAILURE(addDevice(deviceId, "fake", deviceClass, nullptr));
@@ -1418,20 +1417,20 @@
ASSERT_EQ(deviceId, resetArgs.deviceId);
ASSERT_EQ(device->isEnabled(), true);
- disableDevice(deviceId, device);
+ disableDevice(deviceId);
mReader->loopOnce();
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
ASSERT_EQ(deviceId, resetArgs.deviceId);
ASSERT_EQ(device->isEnabled(), false);
- disableDevice(deviceId, device);
+ disableDevice(deviceId);
mReader->loopOnce();
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasNotCalled());
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyConfigurationChangedWasNotCalled());
ASSERT_EQ(device->isEnabled(), false);
- enableDevice(deviceId, device);
+ enableDevice(deviceId);
mReader->loopOnce();
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
ASSERT_EQ(deviceId, resetArgs.deviceId);
@@ -1439,10 +1438,10 @@
}
TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToMappers) {
- FakeInputMapper* mapper = nullptr;
- ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, "fake",
- INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, nullptr));
- mapper->setKeyCodeState(AKEYCODE_A, AKEY_STATE_DOWN);
+ FakeInputMapper& mapper =
+ addDeviceWithFakeInputMapper(1, 0, "fake", INPUT_DEVICE_CLASS_KEYBOARD,
+ AINPUT_SOURCE_KEYBOARD, nullptr);
+ mapper.setKeyCodeState(AKEYCODE_A, AKEY_STATE_DOWN);
ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getKeyCodeState(0,
AINPUT_SOURCE_ANY, AKEYCODE_A))
@@ -1466,10 +1465,10 @@
}
TEST_F(InputReaderTest, GetScanCodeState_ForwardsRequestsToMappers) {
- FakeInputMapper* mapper = nullptr;
- ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, "fake",
- INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, nullptr));
- mapper->setScanCodeState(KEY_A, AKEY_STATE_DOWN);
+ FakeInputMapper& mapper =
+ addDeviceWithFakeInputMapper(1, 0, "fake", INPUT_DEVICE_CLASS_KEYBOARD,
+ AINPUT_SOURCE_KEYBOARD, nullptr);
+ mapper.setScanCodeState(KEY_A, AKEY_STATE_DOWN);
ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getScanCodeState(0,
AINPUT_SOURCE_ANY, KEY_A))
@@ -1493,10 +1492,10 @@
}
TEST_F(InputReaderTest, GetSwitchState_ForwardsRequestsToMappers) {
- FakeInputMapper* mapper = nullptr;
- ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, "fake",
- INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, nullptr));
- mapper->setSwitchState(SW_LID, AKEY_STATE_DOWN);
+ FakeInputMapper& mapper =
+ addDeviceWithFakeInputMapper(1, 0, "fake", INPUT_DEVICE_CLASS_KEYBOARD,
+ AINPUT_SOURCE_KEYBOARD, nullptr);
+ mapper.setSwitchState(SW_LID, AKEY_STATE_DOWN);
ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getSwitchState(0,
AINPUT_SOURCE_ANY, SW_LID))
@@ -1520,12 +1519,12 @@
}
TEST_F(InputReaderTest, MarkSupportedKeyCodes_ForwardsRequestsToMappers) {
- FakeInputMapper* mapper = nullptr;
- ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, "fake",
- INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, nullptr));
+ FakeInputMapper& mapper =
+ addDeviceWithFakeInputMapper(1, 0, "fake", INPUT_DEVICE_CLASS_KEYBOARD,
+ AINPUT_SOURCE_KEYBOARD, nullptr);
- mapper->addSupportedKeyCode(AKEYCODE_A);
- mapper->addSupportedKeyCode(AKEYCODE_B);
+ mapper.addSupportedKeyCode(AKEYCODE_A);
+ mapper.addSupportedKeyCode(AKEYCODE_B);
const int32_t keyCodes[4] = { AKEYCODE_A, AKEYCODE_B, AKEYCODE_1, AKEYCODE_2 };
uint8_t flags[4] = { 0, 0, 0, 1 };
@@ -1565,16 +1564,16 @@
}
TEST_F(InputReaderTest, LoopOnce_ForwardsRawEventsToMappers) {
- FakeInputMapper* mapper = nullptr;
- ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, "fake",
- INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, nullptr));
+ FakeInputMapper& mapper =
+ addDeviceWithFakeInputMapper(1, 0, "fake", INPUT_DEVICE_CLASS_KEYBOARD,
+ AINPUT_SOURCE_KEYBOARD, nullptr);
mFakeEventHub->enqueueEvent(0, 1, EV_KEY, KEY_A, 1);
mReader->loopOnce();
ASSERT_NO_FATAL_FAILURE(mFakeEventHub->assertQueueIsEmpty());
RawEvent event;
- ASSERT_NO_FATAL_FAILURE(mapper->assertProcessWasCalled(&event));
+ ASSERT_NO_FATAL_FAILURE(mapper.assertProcessWasCalled(&event));
ASSERT_EQ(0, event.when);
ASSERT_EQ(1, event.deviceId);
ASSERT_EQ(EV_KEY, event.type);
@@ -1587,8 +1586,7 @@
constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD;
InputDevice* device = mReader->newDevice(deviceId, 0 /*controllerNumber*/, "fake", deviceClass);
// Must add at least one mapper or the device will be ignored!
- FakeInputMapper* mapper = new FakeInputMapper(device, AINPUT_SOURCE_KEYBOARD);
- device->addMapper(mapper);
+ device->addMapper<FakeInputMapper>(AINPUT_SOURCE_KEYBOARD);
mReader->setNextDevice(device);
ASSERT_NO_FATAL_FAILURE(addDevice(deviceId, "fake", deviceClass, nullptr));
@@ -1596,19 +1594,19 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
uint32_t prevSequenceNum = resetArgs.sequenceNum;
- disableDevice(deviceId, device);
+ disableDevice(deviceId);
mReader->loopOnce();
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
ASSERT_TRUE(prevSequenceNum < resetArgs.sequenceNum);
prevSequenceNum = resetArgs.sequenceNum;
- enableDevice(deviceId, device);
+ enableDevice(deviceId);
mReader->loopOnce();
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
ASSERT_TRUE(prevSequenceNum < resetArgs.sequenceNum);
prevSequenceNum = resetArgs.sequenceNum;
- disableDevice(deviceId, device);
+ disableDevice(deviceId);
mReader->loopOnce();
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
ASSERT_TRUE(prevSequenceNum < resetArgs.sequenceNum);
@@ -1621,8 +1619,7 @@
const char* DEVICE_LOCATION = "USB1";
InputDevice* device = mReader->newDevice(deviceId, 0 /*controllerNumber*/, "fake", deviceClass,
DEVICE_LOCATION);
- FakeInputMapper* mapper = new FakeInputMapper(device, AINPUT_SOURCE_TOUCHSCREEN);
- device->addMapper(mapper);
+ FakeInputMapper& mapper = device->addMapper<FakeInputMapper>(AINPUT_SOURCE_TOUCHSCREEN);
mReader->setNextDevice(device);
const uint8_t hdmi1 = 1;
@@ -1645,7 +1642,7 @@
ASSERT_NO_FATAL_FAILURE(addDevice(deviceId, "fake", deviceClass, nullptr));
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyConfigurationChangedWasCalled());
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled());
- ASSERT_NO_FATAL_FAILURE(mapper->assertConfigureWasCalled());
+ ASSERT_NO_FATAL_FAILURE(mapper.assertConfigureWasCalled());
// Device should only dispatch to the specified display.
ASSERT_EQ(deviceId, device->getId());
@@ -1653,14 +1650,13 @@
ASSERT_TRUE(mReader->canDispatchToDisplay(deviceId, SECONDARY_DISPLAY_ID));
// Can't dispatch event from a disabled device.
- disableDevice(deviceId, device);
+ disableDevice(deviceId);
mReader->loopOnce();
ASSERT_FALSE(mReader->canDispatchToDisplay(deviceId, SECONDARY_DISPLAY_ID));
}
// --- InputDeviceTest ---
-
class InputDeviceTest : public testing::Test {
protected:
static const char* DEVICE_NAME;
@@ -1764,21 +1760,19 @@
// Configuration.
mFakeEventHub->addConfigurationProperty(DEVICE_ID, String8("key"), String8("value"));
- FakeInputMapper* mapper1 = new FakeInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD);
- mapper1->setKeyboardType(AINPUT_KEYBOARD_TYPE_ALPHABETIC);
- mapper1->setMetaState(AMETA_ALT_ON);
- mapper1->addSupportedKeyCode(AKEYCODE_A);
- mapper1->addSupportedKeyCode(AKEYCODE_B);
- mapper1->setKeyCodeState(AKEYCODE_A, AKEY_STATE_DOWN);
- mapper1->setKeyCodeState(AKEYCODE_B, AKEY_STATE_UP);
- mapper1->setScanCodeState(2, AKEY_STATE_DOWN);
- mapper1->setScanCodeState(3, AKEY_STATE_UP);
- mapper1->setSwitchState(4, AKEY_STATE_DOWN);
- mDevice->addMapper(mapper1);
+ FakeInputMapper& mapper1 = mDevice->addMapper<FakeInputMapper>(AINPUT_SOURCE_KEYBOARD);
+ mapper1.setKeyboardType(AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+ mapper1.setMetaState(AMETA_ALT_ON);
+ mapper1.addSupportedKeyCode(AKEYCODE_A);
+ mapper1.addSupportedKeyCode(AKEYCODE_B);
+ mapper1.setKeyCodeState(AKEYCODE_A, AKEY_STATE_DOWN);
+ mapper1.setKeyCodeState(AKEYCODE_B, AKEY_STATE_UP);
+ mapper1.setScanCodeState(2, AKEY_STATE_DOWN);
+ mapper1.setScanCodeState(3, AKEY_STATE_UP);
+ mapper1.setSwitchState(4, AKEY_STATE_DOWN);
- FakeInputMapper* mapper2 = new FakeInputMapper(mDevice, AINPUT_SOURCE_TOUCHSCREEN);
- mapper2->setMetaState(AMETA_SHIFT_ON);
- mDevice->addMapper(mapper2);
+ FakeInputMapper& mapper2 = mDevice->addMapper<FakeInputMapper>(AINPUT_SOURCE_TOUCHSCREEN);
+ mapper2.setMetaState(AMETA_SHIFT_ON);
InputReaderConfiguration config;
mDevice->configure(ARBITRARY_TIME, &config, 0);
@@ -1788,13 +1782,13 @@
<< "Device should have read configuration during configuration phase.";
ASSERT_STREQ("value", propertyValue.string());
- ASSERT_NO_FATAL_FAILURE(mapper1->assertConfigureWasCalled());
- ASSERT_NO_FATAL_FAILURE(mapper2->assertConfigureWasCalled());
+ ASSERT_NO_FATAL_FAILURE(mapper1.assertConfigureWasCalled());
+ ASSERT_NO_FATAL_FAILURE(mapper2.assertConfigureWasCalled());
// Reset
mDevice->reset(ARBITRARY_TIME);
- ASSERT_NO_FATAL_FAILURE(mapper1->assertResetWasCalled());
- ASSERT_NO_FATAL_FAILURE(mapper2->assertResetWasCalled());
+ ASSERT_NO_FATAL_FAILURE(mapper1.assertResetWasCalled());
+ ASSERT_NO_FATAL_FAILURE(mapper2.assertResetWasCalled());
NotifyDeviceResetArgs resetArgs;
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
@@ -1850,16 +1844,15 @@
RawEvent event;
mDevice->process(&event, 1);
- ASSERT_NO_FATAL_FAILURE(mapper1->assertProcessWasCalled());
- ASSERT_NO_FATAL_FAILURE(mapper2->assertProcessWasCalled());
+ ASSERT_NO_FATAL_FAILURE(mapper1.assertProcessWasCalled());
+ ASSERT_NO_FATAL_FAILURE(mapper2.assertProcessWasCalled());
}
// A single input device is associated with a specific display. Check that:
// 1. Device is disabled if the viewport corresponding to the associated display is not found
// 2. Device is disabled when setEnabled API is called
TEST_F(InputDeviceTest, Configure_AssignsDisplayPort) {
- FakeInputMapper* mapper = new FakeInputMapper(mDevice, AINPUT_SOURCE_TOUCHSCREEN);
- mDevice->addMapper(mapper);
+ mDevice->addMapper<FakeInputMapper>(AINPUT_SOURCE_TOUCHSCREEN);
// First Configuration.
mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0);
@@ -1944,10 +1937,12 @@
mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), changes);
}
- void addMapperAndConfigure(InputMapper* mapper) {
- mDevice->addMapper(mapper);
+ template <class T, typename... Args>
+ T& addMapperAndConfigure(Args... args) {
+ T& mapper = mDevice->addMapper<T>(args...);
configureDevice(0);
mDevice->reset(ARBITRARY_TIME);
+ return mapper;
}
void setDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height,
@@ -1962,15 +1957,15 @@
mFakePolicy->clearViewports();
}
- static void process(InputMapper* mapper, nsecs_t when, int32_t type,
- int32_t code, int32_t value) {
+ static void process(InputMapper& mapper, nsecs_t when, int32_t type, int32_t code,
+ int32_t value) {
RawEvent event;
event.when = when;
- event.deviceId = mapper->getDeviceId();
+ event.deviceId = mapper.getDeviceId();
event.type = type;
event.code = code;
event.value = value;
- mapper->process(&event);
+ mapper.process(&event);
}
static void assertMotionRange(const InputDeviceInfo& info,
@@ -2024,26 +2019,23 @@
};
TEST_F(SwitchInputMapperTest, GetSources) {
- SwitchInputMapper* mapper = new SwitchInputMapper(mDevice);
- addMapperAndConfigure(mapper);
+ SwitchInputMapper& mapper = addMapperAndConfigure<SwitchInputMapper>();
- ASSERT_EQ(uint32_t(AINPUT_SOURCE_SWITCH), mapper->getSources());
+ ASSERT_EQ(uint32_t(AINPUT_SOURCE_SWITCH), mapper.getSources());
}
TEST_F(SwitchInputMapperTest, GetSwitchState) {
- SwitchInputMapper* mapper = new SwitchInputMapper(mDevice);
- addMapperAndConfigure(mapper);
+ SwitchInputMapper& mapper = addMapperAndConfigure<SwitchInputMapper>();
mFakeEventHub->setSwitchState(DEVICE_ID, SW_LID, 1);
- ASSERT_EQ(1, mapper->getSwitchState(AINPUT_SOURCE_ANY, SW_LID));
+ ASSERT_EQ(1, mapper.getSwitchState(AINPUT_SOURCE_ANY, SW_LID));
mFakeEventHub->setSwitchState(DEVICE_ID, SW_LID, 0);
- ASSERT_EQ(0, mapper->getSwitchState(AINPUT_SOURCE_ANY, SW_LID));
+ ASSERT_EQ(0, mapper.getSwitchState(AINPUT_SOURCE_ANY, SW_LID));
}
TEST_F(SwitchInputMapperTest, Process) {
- SwitchInputMapper* mapper = new SwitchInputMapper(mDevice);
- addMapperAndConfigure(mapper);
+ SwitchInputMapper& mapper = addMapperAndConfigure<SwitchInputMapper>();
process(mapper, ARBITRARY_TIME, EV_SW, SW_LID, 1);
process(mapper, ARBITRARY_TIME, EV_SW, SW_JACK_PHYSICAL_INSERT, 1);
@@ -2068,7 +2060,7 @@
void prepareDisplay(int32_t orientation);
- void testDPadKeyRotation(KeyboardInputMapper* mapper, int32_t originalScanCode,
+ void testDPadKeyRotation(KeyboardInputMapper& mapper, int32_t originalScanCode,
int32_t originalKeyCode, int32_t rotatedKeyCode,
int32_t displayId = ADISPLAY_ID_NONE);
};
@@ -2081,7 +2073,7 @@
orientation, UNIQUE_ID, NO_PORT, ViewportType::VIEWPORT_INTERNAL);
}
-void KeyboardInputMapperTest::testDPadKeyRotation(KeyboardInputMapper* mapper,
+void KeyboardInputMapperTest::testDPadKeyRotation(KeyboardInputMapper& mapper,
int32_t originalScanCode, int32_t originalKeyCode,
int32_t rotatedKeyCode, int32_t displayId) {
NotifyKeyArgs args;
@@ -2102,11 +2094,11 @@
}
TEST_F(KeyboardInputMapperTest, GetSources) {
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
- AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
- addMapperAndConfigure(mapper);
+ KeyboardInputMapper& mapper =
+ addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
+ AINPUT_KEYBOARD_TYPE_ALPHABETIC);
- ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, mapper->getSources());
+ ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, mapper.getSources());
}
TEST_F(KeyboardInputMapperTest, Process_SimpleKeyPress) {
@@ -2115,9 +2107,9 @@
mFakeEventHub->addKey(DEVICE_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE);
mFakeEventHub->addKey(DEVICE_ID, 0, USAGE_A, AKEYCODE_A, POLICY_FLAG_WAKE);
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
- AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
- addMapperAndConfigure(mapper);
+ KeyboardInputMapper& mapper =
+ addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
+ AINPUT_KEYBOARD_TYPE_ALPHABETIC);
// Key down by scan code.
process(mapper, ARBITRARY_TIME, EV_KEY, KEY_HOME, 1);
@@ -2213,38 +2205,38 @@
mFakeEventHub->addKey(DEVICE_ID, KEY_LEFTSHIFT, 0, AKEYCODE_SHIFT_LEFT, 0);
mFakeEventHub->addKey(DEVICE_ID, KEY_A, 0, AKEYCODE_A, 0);
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
- AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
- addMapperAndConfigure(mapper);
+ KeyboardInputMapper& mapper =
+ addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
+ AINPUT_KEYBOARD_TYPE_ALPHABETIC);
// Initial metastate.
- ASSERT_EQ(AMETA_NONE, mapper->getMetaState());
+ ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
// Metakey down.
process(mapper, ARBITRARY_TIME, EV_KEY, KEY_LEFTSHIFT, 1);
NotifyKeyArgs args;
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState);
- ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper->getMetaState());
+ ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper.getMetaState());
ASSERT_NO_FATAL_FAILURE(mFakeContext->assertUpdateGlobalMetaStateWasCalled());
// Key down.
process(mapper, ARBITRARY_TIME + 1, EV_KEY, KEY_A, 1);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState);
- ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper->getMetaState());
+ ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper.getMetaState());
// Key up.
process(mapper, ARBITRARY_TIME + 2, EV_KEY, KEY_A, 0);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState);
- ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper->getMetaState());
+ ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper.getMetaState());
// Metakey up.
process(mapper, ARBITRARY_TIME + 3, EV_KEY, KEY_LEFTSHIFT, 0);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
ASSERT_EQ(AMETA_NONE, args.metaState);
- ASSERT_EQ(AMETA_NONE, mapper->getMetaState());
+ ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
ASSERT_NO_FATAL_FAILURE(mFakeContext->assertUpdateGlobalMetaStateWasCalled());
}
@@ -2254,9 +2246,9 @@
mFakeEventHub->addKey(DEVICE_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0);
mFakeEventHub->addKey(DEVICE_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0);
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
- AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
- addMapperAndConfigure(mapper);
+ KeyboardInputMapper& mapper =
+ addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
+ AINPUT_KEYBOARD_TYPE_ALPHABETIC);
prepareDisplay(DISPLAY_ORIENTATION_90);
ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
@@ -2275,10 +2267,10 @@
mFakeEventHub->addKey(DEVICE_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0);
mFakeEventHub->addKey(DEVICE_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0);
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
- AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
addConfigurationProperty("keyboard.orientationAware", "1");
- addMapperAndConfigure(mapper);
+ KeyboardInputMapper& mapper =
+ addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
+ AINPUT_KEYBOARD_TYPE_ALPHABETIC);
prepareDisplay(DISPLAY_ORIENTATION_0);
ASSERT_NO_FATAL_FAILURE(
@@ -2348,9 +2340,9 @@
// key events should not be associated with a specific display id
mFakeEventHub->addKey(DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
- AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
- addMapperAndConfigure(mapper);
+ KeyboardInputMapper& mapper =
+ addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
+ AINPUT_KEYBOARD_TYPE_ALPHABETIC);
NotifyKeyArgs args;
// Display id should be ADISPLAY_ID_NONE without any display configuration.
@@ -2373,10 +2365,10 @@
// key events should be associated with the internal viewport
mFakeEventHub->addKey(DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
- AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
addConfigurationProperty("keyboard.orientationAware", "1");
- addMapperAndConfigure(mapper);
+ KeyboardInputMapper& mapper =
+ addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
+ AINPUT_KEYBOARD_TYPE_ALPHABETIC);
NotifyKeyArgs args;
// Display id should be ADISPLAY_ID_NONE without any display configuration.
@@ -2402,39 +2394,39 @@
}
TEST_F(KeyboardInputMapperTest, GetKeyCodeState) {
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
- AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
- addMapperAndConfigure(mapper);
+ KeyboardInputMapper& mapper =
+ addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
+ AINPUT_KEYBOARD_TYPE_ALPHABETIC);
mFakeEventHub->setKeyCodeState(DEVICE_ID, AKEYCODE_A, 1);
- ASSERT_EQ(1, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A));
+ ASSERT_EQ(1, mapper.getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A));
mFakeEventHub->setKeyCodeState(DEVICE_ID, AKEYCODE_A, 0);
- ASSERT_EQ(0, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A));
+ ASSERT_EQ(0, mapper.getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A));
}
TEST_F(KeyboardInputMapperTest, GetScanCodeState) {
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
- AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
- addMapperAndConfigure(mapper);
+ KeyboardInputMapper& mapper =
+ addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
+ AINPUT_KEYBOARD_TYPE_ALPHABETIC);
mFakeEventHub->setScanCodeState(DEVICE_ID, KEY_A, 1);
- ASSERT_EQ(1, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_A));
+ ASSERT_EQ(1, mapper.getScanCodeState(AINPUT_SOURCE_ANY, KEY_A));
mFakeEventHub->setScanCodeState(DEVICE_ID, KEY_A, 0);
- ASSERT_EQ(0, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_A));
+ ASSERT_EQ(0, mapper.getScanCodeState(AINPUT_SOURCE_ANY, KEY_A));
}
TEST_F(KeyboardInputMapperTest, MarkSupportedKeyCodes) {
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
- AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
- addMapperAndConfigure(mapper);
+ KeyboardInputMapper& mapper =
+ addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
+ AINPUT_KEYBOARD_TYPE_ALPHABETIC);
mFakeEventHub->addKey(DEVICE_ID, KEY_A, 0, AKEYCODE_A, 0);
const int32_t keyCodes[2] = { AKEYCODE_A, AKEYCODE_B };
uint8_t flags[2] = { 0, 0 };
- ASSERT_TRUE(mapper->markSupportedKeyCodes(AINPUT_SOURCE_ANY, 1, keyCodes, flags));
+ ASSERT_TRUE(mapper.markSupportedKeyCodes(AINPUT_SOURCE_ANY, 1, keyCodes, flags));
ASSERT_TRUE(flags[0]);
ASSERT_FALSE(flags[1]);
}
@@ -2447,9 +2439,9 @@
mFakeEventHub->addKey(DEVICE_ID, KEY_NUMLOCK, 0, AKEYCODE_NUM_LOCK, 0);
mFakeEventHub->addKey(DEVICE_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0);
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
- AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
- addMapperAndConfigure(mapper);
+ KeyboardInputMapper& mapper =
+ addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
+ AINPUT_KEYBOARD_TYPE_ALPHABETIC);
// Initialization should have turned all of the lights off.
ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
@@ -2462,7 +2454,7 @@
ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
- ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper->getMetaState());
+ ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper.getMetaState());
// Toggle num lock on.
process(mapper, ARBITRARY_TIME, EV_KEY, KEY_NUMLOCK, 1);
@@ -2470,7 +2462,7 @@
ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
- ASSERT_EQ(AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON, mapper->getMetaState());
+ ASSERT_EQ(AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON, mapper.getMetaState());
// Toggle caps lock off.
process(mapper, ARBITRARY_TIME, EV_KEY, KEY_CAPSLOCK, 1);
@@ -2478,7 +2470,7 @@
ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
- ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper->getMetaState());
+ ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper.getMetaState());
// Toggle scroll lock on.
process(mapper, ARBITRARY_TIME, EV_KEY, KEY_SCROLLLOCK, 1);
@@ -2486,7 +2478,7 @@
ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
- ASSERT_EQ(AMETA_NUM_LOCK_ON | AMETA_SCROLL_LOCK_ON, mapper->getMetaState());
+ ASSERT_EQ(AMETA_NUM_LOCK_ON | AMETA_SCROLL_LOCK_ON, mapper.getMetaState());
// Toggle num lock off.
process(mapper, ARBITRARY_TIME, EV_KEY, KEY_NUMLOCK, 1);
@@ -2494,7 +2486,7 @@
ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
- ASSERT_EQ(AMETA_SCROLL_LOCK_ON, mapper->getMetaState());
+ ASSERT_EQ(AMETA_SCROLL_LOCK_ON, mapper.getMetaState());
// Toggle scroll lock off.
process(mapper, ARBITRARY_TIME, EV_KEY, KEY_SCROLLLOCK, 1);
@@ -2502,7 +2494,7 @@
ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
- ASSERT_EQ(AMETA_NONE, mapper->getMetaState());
+ ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
}
TEST_F(KeyboardInputMapperTest, Configure_AssignsDisplayPort) {
@@ -2527,13 +2519,13 @@
mFakeEventHub->addKey(SECOND_DEVICE_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0);
mFakeEventHub->addKey(SECOND_DEVICE_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0);
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD,
- AINPUT_KEYBOARD_TYPE_ALPHABETIC);
- addMapperAndConfigure(mapper);
+ KeyboardInputMapper& mapper =
+ addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
+ AINPUT_KEYBOARD_TYPE_ALPHABETIC);
- KeyboardInputMapper* mapper2 = new KeyboardInputMapper(device2.get(), AINPUT_SOURCE_KEYBOARD,
- AINPUT_KEYBOARD_TYPE_ALPHABETIC);
- device2->addMapper(mapper2);
+ KeyboardInputMapper& mapper2 =
+ device2->addMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
+ AINPUT_KEYBOARD_TYPE_ALPHABETIC);
device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0 /*changes*/);
device2->reset(ARBITRARY_TIME);
@@ -2593,9 +2585,9 @@
mFakeEventHub->addKey(DEVICE_ID, KEY_PLAY, 0, AKEYCODE_MEDIA_PLAY, 0);
mFakeEventHub->addKey(DEVICE_ID, KEY_PLAYPAUSE, 0, AKEYCODE_MEDIA_PLAY_PAUSE, POLICY_FLAG_WAKE);
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD,
- AINPUT_KEYBOARD_TYPE_ALPHABETIC);
- addMapperAndConfigure(mapper);
+ KeyboardInputMapper& mapper =
+ addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
+ AINPUT_KEYBOARD_TYPE_ALPHABETIC);
process(mapper, ARBITRARY_TIME, EV_KEY, KEY_HOME, 1);
NotifyKeyArgs args;
@@ -2631,10 +2623,10 @@
mFakeEventHub->addKey(DEVICE_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0);
mFakeEventHub->addKey(DEVICE_ID, KEY_PLAY, 0, AKEYCODE_MEDIA_PLAY, POLICY_FLAG_WAKE);
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD,
- AINPUT_KEYBOARD_TYPE_ALPHABETIC);
addConfigurationProperty("keyboard.doNotWakeByDefault", "1");
- addMapperAndConfigure(mapper);
+ KeyboardInputMapper& mapper =
+ addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
+ AINPUT_KEYBOARD_TYPE_ALPHABETIC);
process(mapper, ARBITRARY_TIME, EV_KEY, KEY_HOME, 1);
NotifyKeyArgs args;
@@ -2677,8 +2669,8 @@
mFakePolicy->setPointerController(mDevice->getId(), mFakePointerController);
}
- void testMotionRotation(CursorInputMapper* mapper,
- int32_t originalX, int32_t originalY, int32_t rotatedX, int32_t rotatedY);
+ void testMotionRotation(CursorInputMapper& mapper, int32_t originalX, int32_t originalY,
+ int32_t rotatedX, int32_t rotatedY);
void prepareDisplay(int32_t orientation) {
const std::string uniqueId = "local:0";
@@ -2690,8 +2682,9 @@
const int32_t CursorInputMapperTest::TRACKBALL_MOVEMENT_THRESHOLD = 6;
-void CursorInputMapperTest::testMotionRotation(CursorInputMapper* mapper,
- int32_t originalX, int32_t originalY, int32_t rotatedX, int32_t rotatedY) {
+void CursorInputMapperTest::testMotionRotation(CursorInputMapper& mapper, int32_t originalX,
+ int32_t originalY, int32_t rotatedX,
+ int32_t rotatedY) {
NotifyMotionArgs args;
process(mapper, ARBITRARY_TIME, EV_REL, REL_X, originalX);
@@ -2706,28 +2699,25 @@
}
TEST_F(CursorInputMapperTest, WhenModeIsPointer_GetSources_ReturnsMouse) {
- CursorInputMapper* mapper = new CursorInputMapper(mDevice);
addConfigurationProperty("cursor.mode", "pointer");
- addMapperAndConfigure(mapper);
+ CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
- ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper->getSources());
+ ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper.getSources());
}
TEST_F(CursorInputMapperTest, WhenModeIsNavigation_GetSources_ReturnsTrackball) {
- CursorInputMapper* mapper = new CursorInputMapper(mDevice);
addConfigurationProperty("cursor.mode", "navigation");
- addMapperAndConfigure(mapper);
+ CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
- ASSERT_EQ(AINPUT_SOURCE_TRACKBALL, mapper->getSources());
+ ASSERT_EQ(AINPUT_SOURCE_TRACKBALL, mapper.getSources());
}
TEST_F(CursorInputMapperTest, WhenModeIsPointer_PopulateDeviceInfo_ReturnsRangeFromPointerController) {
- CursorInputMapper* mapper = new CursorInputMapper(mDevice);
addConfigurationProperty("cursor.mode", "pointer");
- addMapperAndConfigure(mapper);
+ CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
InputDeviceInfo info;
- mapper->populateDeviceInfo(&info);
+ mapper.populateDeviceInfo(&info);
// Initially there may not be a valid motion range.
ASSERT_EQ(nullptr, info.getMotionRange(AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_MOUSE));
@@ -2739,7 +2729,7 @@
mFakePointerController->setBounds(1, 2, 800 - 1, 480 - 1);
InputDeviceInfo info2;
- mapper->populateDeviceInfo(&info2);
+ mapper.populateDeviceInfo(&info2);
ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2,
AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_MOUSE,
@@ -2753,12 +2743,11 @@
}
TEST_F(CursorInputMapperTest, WhenModeIsNavigation_PopulateDeviceInfo_ReturnsScaledRange) {
- CursorInputMapper* mapper = new CursorInputMapper(mDevice);
addConfigurationProperty("cursor.mode", "navigation");
- addMapperAndConfigure(mapper);
+ CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
InputDeviceInfo info;
- mapper->populateDeviceInfo(&info);
+ mapper.populateDeviceInfo(&info);
ASSERT_NO_FATAL_FAILURE(assertMotionRange(info,
AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_TRACKBALL,
@@ -2772,9 +2761,8 @@
}
TEST_F(CursorInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaState) {
- CursorInputMapper* mapper = new CursorInputMapper(mDevice);
addConfigurationProperty("cursor.mode", "navigation");
- addMapperAndConfigure(mapper);
+ CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON);
@@ -2865,9 +2853,8 @@
}
TEST_F(CursorInputMapperTest, Process_ShouldHandleIndependentXYUpdates) {
- CursorInputMapper* mapper = new CursorInputMapper(mDevice);
addConfigurationProperty("cursor.mode", "navigation");
- addMapperAndConfigure(mapper);
+ CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
NotifyMotionArgs args;
@@ -2889,9 +2876,8 @@
}
TEST_F(CursorInputMapperTest, Process_ShouldHandleIndependentButtonUpdates) {
- CursorInputMapper* mapper = new CursorInputMapper(mDevice);
addConfigurationProperty("cursor.mode", "navigation");
- addMapperAndConfigure(mapper);
+ CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
NotifyMotionArgs args;
@@ -2923,9 +2909,8 @@
}
TEST_F(CursorInputMapperTest, Process_ShouldHandleCombinedXYAndButtonUpdates) {
- CursorInputMapper* mapper = new CursorInputMapper(mDevice);
addConfigurationProperty("cursor.mode", "navigation");
- addMapperAndConfigure(mapper);
+ CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
NotifyMotionArgs args;
@@ -2971,9 +2956,8 @@
}
TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateMotions) {
- CursorInputMapper* mapper = new CursorInputMapper(mDevice);
addConfigurationProperty("cursor.mode", "navigation");
- addMapperAndConfigure(mapper);
+ CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
prepareDisplay(DISPLAY_ORIENTATION_90);
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, 1));
@@ -2987,10 +2971,9 @@
}
TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldRotateMotions) {
- CursorInputMapper* mapper = new CursorInputMapper(mDevice);
addConfigurationProperty("cursor.mode", "navigation");
addConfigurationProperty("cursor.orientationAware", "1");
- addMapperAndConfigure(mapper);
+ CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
prepareDisplay(DISPLAY_ORIENTATION_0);
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, 1));
@@ -3034,9 +3017,8 @@
}
TEST_F(CursorInputMapperTest, Process_ShouldHandleAllButtons) {
- CursorInputMapper* mapper = new CursorInputMapper(mDevice);
addConfigurationProperty("cursor.mode", "pointer");
- addMapperAndConfigure(mapper);
+ CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1);
mFakePointerController->setPosition(100, 200);
@@ -3322,9 +3304,8 @@
}
TEST_F(CursorInputMapperTest, Process_WhenModeIsPointer_ShouldMoveThePointerAround) {
- CursorInputMapper* mapper = new CursorInputMapper(mDevice);
addConfigurationProperty("cursor.mode", "pointer");
- addMapperAndConfigure(mapper);
+ CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1);
mFakePointerController->setPosition(100, 200);
@@ -3344,10 +3325,9 @@
}
TEST_F(CursorInputMapperTest, Process_PointerCapture) {
- CursorInputMapper* mapper = new CursorInputMapper(mDevice);
addConfigurationProperty("cursor.mode", "pointer");
mFakePolicy->setPointerCapture(true);
- addMapperAndConfigure(mapper);
+ CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
NotifyDeviceResetArgs resetArgs;
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
@@ -3433,8 +3413,7 @@
}
TEST_F(CursorInputMapperTest, Process_ShouldHandleDisplayId) {
- CursorInputMapper* mapper = new CursorInputMapper(mDevice);
- addMapperAndConfigure(mapper);
+ CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
// Setup for second display.
constexpr int32_t SECOND_DISPLAY_ID = 1;
@@ -3462,7 +3441,6 @@
ASSERT_EQ(SECOND_DISPLAY_ID, args.displayId);
}
-
// --- TouchInputMapperTest ---
class TouchInputMapperTest : public InputMapperTest {
@@ -3637,15 +3615,15 @@
void prepareButtons();
void prepareAxes(int axes);
- void processDown(SingleTouchInputMapper* mapper, int32_t x, int32_t y);
- void processMove(SingleTouchInputMapper* mapper, int32_t x, int32_t y);
- void processUp(SingleTouchInputMapper* mappery);
- void processPressure(SingleTouchInputMapper* mapper, int32_t pressure);
- void processToolMajor(SingleTouchInputMapper* mapper, int32_t toolMajor);
- void processDistance(SingleTouchInputMapper* mapper, int32_t distance);
- void processTilt(SingleTouchInputMapper* mapper, int32_t tiltX, int32_t tiltY);
- void processKey(SingleTouchInputMapper* mapper, int32_t code, int32_t value);
- void processSync(SingleTouchInputMapper* mapper);
+ void processDown(SingleTouchInputMapper& mapper, int32_t x, int32_t y);
+ void processMove(SingleTouchInputMapper& mapper, int32_t x, int32_t y);
+ void processUp(SingleTouchInputMapper& mappery);
+ void processPressure(SingleTouchInputMapper& mapper, int32_t pressure);
+ void processToolMajor(SingleTouchInputMapper& mapper, int32_t toolMajor);
+ void processDistance(SingleTouchInputMapper& mapper, int32_t distance);
+ void processTilt(SingleTouchInputMapper& mapper, int32_t tiltX, int32_t tiltY);
+ void processKey(SingleTouchInputMapper& mapper, int32_t code, int32_t value);
+ void processSync(SingleTouchInputMapper& mapper);
};
void SingleTouchInputMapperTest::prepareButtons() {
@@ -3679,103 +3657,95 @@
}
}
-void SingleTouchInputMapperTest::processDown(SingleTouchInputMapper* mapper, int32_t x, int32_t y) {
+void SingleTouchInputMapperTest::processDown(SingleTouchInputMapper& mapper, int32_t x, int32_t y) {
process(mapper, ARBITRARY_TIME, EV_KEY, BTN_TOUCH, 1);
process(mapper, ARBITRARY_TIME, EV_ABS, ABS_X, x);
process(mapper, ARBITRARY_TIME, EV_ABS, ABS_Y, y);
}
-void SingleTouchInputMapperTest::processMove(SingleTouchInputMapper* mapper, int32_t x, int32_t y) {
+void SingleTouchInputMapperTest::processMove(SingleTouchInputMapper& mapper, int32_t x, int32_t y) {
process(mapper, ARBITRARY_TIME, EV_ABS, ABS_X, x);
process(mapper, ARBITRARY_TIME, EV_ABS, ABS_Y, y);
}
-void SingleTouchInputMapperTest::processUp(SingleTouchInputMapper* mapper) {
+void SingleTouchInputMapperTest::processUp(SingleTouchInputMapper& mapper) {
process(mapper, ARBITRARY_TIME, EV_KEY, BTN_TOUCH, 0);
}
-void SingleTouchInputMapperTest::processPressure(
- SingleTouchInputMapper* mapper, int32_t pressure) {
+void SingleTouchInputMapperTest::processPressure(SingleTouchInputMapper& mapper, int32_t pressure) {
process(mapper, ARBITRARY_TIME, EV_ABS, ABS_PRESSURE, pressure);
}
-void SingleTouchInputMapperTest::processToolMajor(
- SingleTouchInputMapper* mapper, int32_t toolMajor) {
+void SingleTouchInputMapperTest::processToolMajor(SingleTouchInputMapper& mapper,
+ int32_t toolMajor) {
process(mapper, ARBITRARY_TIME, EV_ABS, ABS_TOOL_WIDTH, toolMajor);
}
-void SingleTouchInputMapperTest::processDistance(
- SingleTouchInputMapper* mapper, int32_t distance) {
+void SingleTouchInputMapperTest::processDistance(SingleTouchInputMapper& mapper, int32_t distance) {
process(mapper, ARBITRARY_TIME, EV_ABS, ABS_DISTANCE, distance);
}
-void SingleTouchInputMapperTest::processTilt(
- SingleTouchInputMapper* mapper, int32_t tiltX, int32_t tiltY) {
+void SingleTouchInputMapperTest::processTilt(SingleTouchInputMapper& mapper, int32_t tiltX,
+ int32_t tiltY) {
process(mapper, ARBITRARY_TIME, EV_ABS, ABS_TILT_X, tiltX);
process(mapper, ARBITRARY_TIME, EV_ABS, ABS_TILT_Y, tiltY);
}
-void SingleTouchInputMapperTest::processKey(
- SingleTouchInputMapper* mapper, int32_t code, int32_t value) {
+void SingleTouchInputMapperTest::processKey(SingleTouchInputMapper& mapper, int32_t code,
+ int32_t value) {
process(mapper, ARBITRARY_TIME, EV_KEY, code, value);
}
-void SingleTouchInputMapperTest::processSync(SingleTouchInputMapper* mapper) {
+void SingleTouchInputMapperTest::processSync(SingleTouchInputMapper& mapper) {
process(mapper, ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
}
-
TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndNotACursor_ReturnsPointer) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
prepareButtons();
prepareAxes(POSITION);
- addMapperAndConfigure(mapper);
+ SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
- ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper->getSources());
+ ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper.getSources());
}
TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndIsACursor_ReturnsTouchPad) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
mFakeEventHub->addRelativeAxis(DEVICE_ID, REL_X);
mFakeEventHub->addRelativeAxis(DEVICE_ID, REL_Y);
prepareButtons();
prepareAxes(POSITION);
- addMapperAndConfigure(mapper);
+ SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
- ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper->getSources());
+ ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper.getSources());
}
TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsTouchPad_ReturnsTouchPad) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
prepareButtons();
prepareAxes(POSITION);
addConfigurationProperty("touch.deviceType", "touchPad");
- addMapperAndConfigure(mapper);
+ SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
- ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper->getSources());
+ ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper.getSources());
}
TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsTouchScreen_ReturnsTouchScreen) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
prepareButtons();
prepareAxes(POSITION);
addConfigurationProperty("touch.deviceType", "touchScreen");
- addMapperAndConfigure(mapper);
+ SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
- ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper->getSources());
+ ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper.getSources());
}
TEST_F(SingleTouchInputMapperTest, GetKeyCodeState) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareButtons();
prepareAxes(POSITION);
prepareVirtualKeys();
- addMapperAndConfigure(mapper);
+ SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
// Unknown key.
- ASSERT_EQ(AKEY_STATE_UNKNOWN, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A));
+ ASSERT_EQ(AKEY_STATE_UNKNOWN, mapper.getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A));
// Virtual key is down.
int32_t x = toRawX(VIRTUAL_KEYS[0].centerX);
@@ -3784,27 +3754,26 @@
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled());
- ASSERT_EQ(AKEY_STATE_VIRTUAL, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_HOME));
+ ASSERT_EQ(AKEY_STATE_VIRTUAL, mapper.getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_HOME));
// Virtual key is up.
processUp(mapper);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled());
- ASSERT_EQ(AKEY_STATE_UP, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_HOME));
+ ASSERT_EQ(AKEY_STATE_UP, mapper.getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_HOME));
}
TEST_F(SingleTouchInputMapperTest, GetScanCodeState) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareButtons();
prepareAxes(POSITION);
prepareVirtualKeys();
- addMapperAndConfigure(mapper);
+ SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
// Unknown key.
- ASSERT_EQ(AKEY_STATE_UNKNOWN, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_A));
+ ASSERT_EQ(AKEY_STATE_UNKNOWN, mapper.getScanCodeState(AINPUT_SOURCE_ANY, KEY_A));
// Virtual key is down.
int32_t x = toRawX(VIRTUAL_KEYS[0].centerX);
@@ -3813,40 +3782,38 @@
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled());
- ASSERT_EQ(AKEY_STATE_VIRTUAL, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_HOME));
+ ASSERT_EQ(AKEY_STATE_VIRTUAL, mapper.getScanCodeState(AINPUT_SOURCE_ANY, KEY_HOME));
// Virtual key is up.
processUp(mapper);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled());
- ASSERT_EQ(AKEY_STATE_UP, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_HOME));
+ ASSERT_EQ(AKEY_STATE_UP, mapper.getScanCodeState(AINPUT_SOURCE_ANY, KEY_HOME));
}
TEST_F(SingleTouchInputMapperTest, MarkSupportedKeyCodes) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareButtons();
prepareAxes(POSITION);
prepareVirtualKeys();
- addMapperAndConfigure(mapper);
+ SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
const int32_t keys[2] = { AKEYCODE_HOME, AKEYCODE_A };
uint8_t flags[2] = { 0, 0 };
- ASSERT_TRUE(mapper->markSupportedKeyCodes(AINPUT_SOURCE_ANY, 2, keys, flags));
+ ASSERT_TRUE(mapper.markSupportedKeyCodes(AINPUT_SOURCE_ANY, 2, keys, flags));
ASSERT_TRUE(flags[0]);
ASSERT_FALSE(flags[1]);
}
TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndReleasedNormally_SendsKeyDownAndKeyUp) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareButtons();
prepareAxes(POSITION);
prepareVirtualKeys();
- addMapperAndConfigure(mapper);
+ SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON);
@@ -3891,13 +3858,12 @@
}
TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndMovedOutOfBounds_SendsKeyDownAndKeyCancel) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareButtons();
prepareAxes(POSITION);
prepareVirtualKeys();
- addMapperAndConfigure(mapper);
+ SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON);
@@ -4013,13 +3979,12 @@
}
TEST_F(SingleTouchInputMapperTest, Process_WhenTouchStartsOutsideDisplayAndMovesIn_SendsDownAsTouchEntersDisplay) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareButtons();
prepareAxes(POSITION);
prepareVirtualKeys();
- addMapperAndConfigure(mapper);
+ SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON);
@@ -4087,7 +4052,6 @@
}
TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture_VirtualDisplay) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
addConfigurationProperty("touch.displayId", VIRTUAL_DISPLAY_UNIQUE_ID);
@@ -4095,7 +4059,7 @@
prepareButtons();
prepareAxes(POSITION);
prepareVirtualKeys();
- addMapperAndConfigure(mapper);
+ SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON);
@@ -4186,13 +4150,12 @@
}
TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareButtons();
prepareAxes(POSITION);
prepareVirtualKeys();
- addMapperAndConfigure(mapper);
+ SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON);
@@ -4277,12 +4240,11 @@
}
TEST_F(SingleTouchInputMapperTest, Process_WhenNotOrientationAware_DoesNotRotateMotions) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareButtons();
prepareAxes(POSITION);
addConfigurationProperty("touch.orientationAware", "0");
- addMapperAndConfigure(mapper);
+ SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
NotifyMotionArgs args;
@@ -4301,11 +4263,10 @@
}
TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_RotatesMotions) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareButtons();
prepareAxes(POSITION);
- addMapperAndConfigure(mapper);
+ SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
NotifyMotionArgs args;
@@ -4367,12 +4328,11 @@
}
TEST_F(SingleTouchInputMapperTest, Process_AllAxes_DefaultCalibration) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareButtons();
prepareAxes(POSITION | PRESSURE | TOOL | DISTANCE | TILT);
- addMapperAndConfigure(mapper);
+ SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
// These calculations are based on the input device calibration documentation.
int32_t rawX = 100;
@@ -4412,13 +4372,12 @@
}
TEST_F(SingleTouchInputMapperTest, Process_XYAxes_AffineCalibration) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareLocationCalibration();
prepareButtons();
prepareAxes(POSITION);
- addMapperAndConfigure(mapper);
+ SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
int32_t rawX = 100;
int32_t rawY = 200;
@@ -4436,12 +4395,11 @@
}
TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllButtons) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareButtons();
prepareAxes(POSITION);
- addMapperAndConfigure(mapper);
+ SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
NotifyMotionArgs motionArgs;
NotifyKeyArgs keyArgs;
@@ -4680,12 +4638,11 @@
}
TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllToolTypes) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareButtons();
prepareAxes(POSITION);
- addMapperAndConfigure(mapper);
+ SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
NotifyMotionArgs motionArgs;
@@ -4816,13 +4773,12 @@
}
TEST_F(SingleTouchInputMapperTest, Process_WhenBtnTouchPresent_HoversIfItsValueIsZero) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareButtons();
prepareAxes(POSITION);
mFakeEventHub->addKey(DEVICE_ID, BTN_TOOL_FINGER, 0, AKEYCODE_UNKNOWN, 0);
- addMapperAndConfigure(mapper);
+ SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
NotifyMotionArgs motionArgs;
@@ -4889,12 +4845,11 @@
}
TEST_F(SingleTouchInputMapperTest, Process_WhenAbsPressureIsPresent_HoversIfItsValueIsZero) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareButtons();
prepareAxes(POSITION | PRESSURE);
- addMapperAndConfigure(mapper);
+ SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
NotifyMotionArgs motionArgs;
@@ -4960,27 +4915,26 @@
toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
}
-
// --- MultiTouchInputMapperTest ---
class MultiTouchInputMapperTest : public TouchInputMapperTest {
protected:
void prepareAxes(int axes);
- void processPosition(MultiTouchInputMapper* mapper, int32_t x, int32_t y);
- void processTouchMajor(MultiTouchInputMapper* mapper, int32_t touchMajor);
- void processTouchMinor(MultiTouchInputMapper* mapper, int32_t touchMinor);
- void processToolMajor(MultiTouchInputMapper* mapper, int32_t toolMajor);
- void processToolMinor(MultiTouchInputMapper* mapper, int32_t toolMinor);
- void processOrientation(MultiTouchInputMapper* mapper, int32_t orientation);
- void processPressure(MultiTouchInputMapper* mapper, int32_t pressure);
- void processDistance(MultiTouchInputMapper* mapper, int32_t distance);
- void processId(MultiTouchInputMapper* mapper, int32_t id);
- void processSlot(MultiTouchInputMapper* mapper, int32_t slot);
- void processToolType(MultiTouchInputMapper* mapper, int32_t toolType);
- void processKey(MultiTouchInputMapper* mapper, int32_t code, int32_t value);
- void processMTSync(MultiTouchInputMapper* mapper);
- void processSync(MultiTouchInputMapper* mapper);
+ void processPosition(MultiTouchInputMapper& mapper, int32_t x, int32_t y);
+ void processTouchMajor(MultiTouchInputMapper& mapper, int32_t touchMajor);
+ void processTouchMinor(MultiTouchInputMapper& mapper, int32_t touchMinor);
+ void processToolMajor(MultiTouchInputMapper& mapper, int32_t toolMajor);
+ void processToolMinor(MultiTouchInputMapper& mapper, int32_t toolMinor);
+ void processOrientation(MultiTouchInputMapper& mapper, int32_t orientation);
+ void processPressure(MultiTouchInputMapper& mapper, int32_t pressure);
+ void processDistance(MultiTouchInputMapper& mapper, int32_t distance);
+ void processId(MultiTouchInputMapper& mapper, int32_t id);
+ void processSlot(MultiTouchInputMapper& mapper, int32_t slot);
+ void processToolType(MultiTouchInputMapper& mapper, int32_t toolType);
+ void processKey(MultiTouchInputMapper& mapper, int32_t code, int32_t value);
+ void processMTSync(MultiTouchInputMapper& mapper);
+ void processSync(MultiTouchInputMapper& mapper);
};
void MultiTouchInputMapperTest::prepareAxes(int axes) {
@@ -5033,83 +4987,74 @@
}
}
-void MultiTouchInputMapperTest::processPosition(
- MultiTouchInputMapper* mapper, int32_t x, int32_t y) {
+void MultiTouchInputMapperTest::processPosition(MultiTouchInputMapper& mapper, int32_t x,
+ int32_t y) {
process(mapper, ARBITRARY_TIME, EV_ABS, ABS_MT_POSITION_X, x);
process(mapper, ARBITRARY_TIME, EV_ABS, ABS_MT_POSITION_Y, y);
}
-void MultiTouchInputMapperTest::processTouchMajor(
- MultiTouchInputMapper* mapper, int32_t touchMajor) {
+void MultiTouchInputMapperTest::processTouchMajor(MultiTouchInputMapper& mapper,
+ int32_t touchMajor) {
process(mapper, ARBITRARY_TIME, EV_ABS, ABS_MT_TOUCH_MAJOR, touchMajor);
}
-void MultiTouchInputMapperTest::processTouchMinor(
- MultiTouchInputMapper* mapper, int32_t touchMinor) {
+void MultiTouchInputMapperTest::processTouchMinor(MultiTouchInputMapper& mapper,
+ int32_t touchMinor) {
process(mapper, ARBITRARY_TIME, EV_ABS, ABS_MT_TOUCH_MINOR, touchMinor);
}
-void MultiTouchInputMapperTest::processToolMajor(
- MultiTouchInputMapper* mapper, int32_t toolMajor) {
+void MultiTouchInputMapperTest::processToolMajor(MultiTouchInputMapper& mapper, int32_t toolMajor) {
process(mapper, ARBITRARY_TIME, EV_ABS, ABS_MT_WIDTH_MAJOR, toolMajor);
}
-void MultiTouchInputMapperTest::processToolMinor(
- MultiTouchInputMapper* mapper, int32_t toolMinor) {
+void MultiTouchInputMapperTest::processToolMinor(MultiTouchInputMapper& mapper, int32_t toolMinor) {
process(mapper, ARBITRARY_TIME, EV_ABS, ABS_MT_WIDTH_MINOR, toolMinor);
}
-void MultiTouchInputMapperTest::processOrientation(
- MultiTouchInputMapper* mapper, int32_t orientation) {
+void MultiTouchInputMapperTest::processOrientation(MultiTouchInputMapper& mapper,
+ int32_t orientation) {
process(mapper, ARBITRARY_TIME, EV_ABS, ABS_MT_ORIENTATION, orientation);
}
-void MultiTouchInputMapperTest::processPressure(
- MultiTouchInputMapper* mapper, int32_t pressure) {
+void MultiTouchInputMapperTest::processPressure(MultiTouchInputMapper& mapper, int32_t pressure) {
process(mapper, ARBITRARY_TIME, EV_ABS, ABS_MT_PRESSURE, pressure);
}
-void MultiTouchInputMapperTest::processDistance(
- MultiTouchInputMapper* mapper, int32_t distance) {
+void MultiTouchInputMapperTest::processDistance(MultiTouchInputMapper& mapper, int32_t distance) {
process(mapper, ARBITRARY_TIME, EV_ABS, ABS_MT_DISTANCE, distance);
}
-void MultiTouchInputMapperTest::processId(
- MultiTouchInputMapper* mapper, int32_t id) {
+void MultiTouchInputMapperTest::processId(MultiTouchInputMapper& mapper, int32_t id) {
process(mapper, ARBITRARY_TIME, EV_ABS, ABS_MT_TRACKING_ID, id);
}
-void MultiTouchInputMapperTest::processSlot(
- MultiTouchInputMapper* mapper, int32_t slot) {
+void MultiTouchInputMapperTest::processSlot(MultiTouchInputMapper& mapper, int32_t slot) {
process(mapper, ARBITRARY_TIME, EV_ABS, ABS_MT_SLOT, slot);
}
-void MultiTouchInputMapperTest::processToolType(
- MultiTouchInputMapper* mapper, int32_t toolType) {
+void MultiTouchInputMapperTest::processToolType(MultiTouchInputMapper& mapper, int32_t toolType) {
process(mapper, ARBITRARY_TIME, EV_ABS, ABS_MT_TOOL_TYPE, toolType);
}
-void MultiTouchInputMapperTest::processKey(
- MultiTouchInputMapper* mapper, int32_t code, int32_t value) {
+void MultiTouchInputMapperTest::processKey(MultiTouchInputMapper& mapper, int32_t code,
+ int32_t value) {
process(mapper, ARBITRARY_TIME, EV_KEY, code, value);
}
-void MultiTouchInputMapperTest::processMTSync(MultiTouchInputMapper* mapper) {
+void MultiTouchInputMapperTest::processMTSync(MultiTouchInputMapper& mapper) {
process(mapper, ARBITRARY_TIME, EV_SYN, SYN_MT_REPORT, 0);
}
-void MultiTouchInputMapperTest::processSync(MultiTouchInputMapper* mapper) {
+void MultiTouchInputMapperTest::processSync(MultiTouchInputMapper& mapper) {
process(mapper, ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
}
-
TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackingIds) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
- addMapperAndConfigure(mapper);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON);
@@ -5381,12 +5326,11 @@
}
TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingIds) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION | ID);
prepareVirtualKeys();
- addMapperAndConfigure(mapper);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON);
@@ -5557,12 +5501,11 @@
}
TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithSlots) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION | ID | SLOT);
prepareVirtualKeys();
- addMapperAndConfigure(mapper);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON);
@@ -5728,11 +5671,10 @@
}
TEST_F(MultiTouchInputMapperTest, Process_AllAxes_WithDefaultCalibration) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION | TOUCH | TOOL | PRESSURE | ORIENTATION | ID | MINOR | DISTANCE);
- addMapperAndConfigure(mapper);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
// These calculations are based on the input device calibration documentation.
int32_t rawX = 100;
@@ -5778,12 +5720,11 @@
}
TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_GeometricCalibration) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION | TOUCH | TOOL | MINOR);
addConfigurationProperty("touch.size.calibration", "geometric");
- addMapperAndConfigure(mapper);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
// These calculations are based on the input device calibration documentation.
int32_t rawX = 100;
@@ -5816,7 +5757,6 @@
}
TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_SummedLinearCalibration) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION | TOUCH | TOOL);
@@ -5824,7 +5764,7 @@
addConfigurationProperty("touch.size.scale", "10");
addConfigurationProperty("touch.size.bias", "160");
addConfigurationProperty("touch.size.isSummed", "1");
- addMapperAndConfigure(mapper);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
// These calculations are based on the input device calibration documentation.
// Note: We only provide a single common touch/tool value because the device is assumed
@@ -5869,14 +5809,13 @@
}
TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_AreaCalibration) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION | TOUCH | TOOL);
addConfigurationProperty("touch.size.calibration", "area");
addConfigurationProperty("touch.size.scale", "43");
addConfigurationProperty("touch.size.bias", "3");
- addMapperAndConfigure(mapper);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
// These calculations are based on the input device calibration documentation.
int32_t rawX = 100;
@@ -5903,16 +5842,15 @@
}
TEST_F(MultiTouchInputMapperTest, Process_PressureAxis_AmplitudeCalibration) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION | PRESSURE);
addConfigurationProperty("touch.pressure.calibration", "amplitude");
addConfigurationProperty("touch.pressure.scale", "0.01");
- addMapperAndConfigure(mapper);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
InputDeviceInfo info;
- mapper->populateDeviceInfo(&info);
+ mapper.populateDeviceInfo(&info);
ASSERT_NO_FATAL_FAILURE(assertMotionRange(info,
AINPUT_MOTION_RANGE_PRESSURE, AINPUT_SOURCE_TOUCHSCREEN,
0.0f, RAW_PRESSURE_MAX * 0.01, 0.0f, 0.0f));
@@ -5938,11 +5876,10 @@
}
TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllButtons) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION | ID | SLOT);
- addMapperAndConfigure(mapper);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
NotifyMotionArgs motionArgs;
NotifyKeyArgs keyArgs;
@@ -6182,11 +6119,10 @@
}
TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllToolTypes) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION | ID | SLOT | TOOL_TYPE);
- addMapperAndConfigure(mapper);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
NotifyMotionArgs motionArgs;
@@ -6333,12 +6269,11 @@
}
TEST_F(MultiTouchInputMapperTest, Process_WhenBtnTouchPresent_HoversIfItsValueIsZero) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION | ID | SLOT);
mFakeEventHub->addKey(DEVICE_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0);
- addMapperAndConfigure(mapper);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
NotifyMotionArgs motionArgs;
@@ -6405,11 +6340,10 @@
}
TEST_F(MultiTouchInputMapperTest, Process_WhenAbsMTPressureIsPresent_HoversIfItsValueIsZero) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION | ID | SLOT | PRESSURE);
- addMapperAndConfigure(mapper);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
NotifyMotionArgs motionArgs;
@@ -6482,7 +6416,6 @@
* This can be checked by looking at the displayId of the resulting NotifyMotionArgs.
*/
TEST_F(MultiTouchInputMapperTest, Configure_AssignsDisplayPort) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
const std::string usb2 = "USB2";
const uint8_t hdmi1 = 0;
const uint8_t hdmi2 = 1;
@@ -6491,7 +6424,7 @@
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareAxes(POSITION);
- addMapperAndConfigure(mapper);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
mFakePolicy->addInputPortAssociation(DEVICE_LOCATION, hdmi1);
mFakePolicy->addInputPortAssociation(usb2, hdmi2);
@@ -6522,14 +6455,13 @@
* Expect fallback to internal viewport if device is external and external viewport is not present.
*/
TEST_F(MultiTouchInputMapperTest, Viewports_Fallback) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
prepareAxes(POSITION);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
mDevice->setExternal(true);
- addMapperAndConfigure(mapper);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
- ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper->getSources());
+ ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper.getSources());
NotifyMotionArgs motionArgs;
@@ -6559,13 +6491,12 @@
mFakePolicy->setDefaultPointerDisplayId(SECONDARY_DISPLAY_ID);
prepareSecondaryDisplay(ViewportType::VIEWPORT_EXTERNAL);
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION);
- addMapperAndConfigure(mapper);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
// Check source is mouse that would obtain the PointerController.
- ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper->getSources());
+ ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper.getSources());
NotifyMotionArgs motionArgs;
processPosition(mapper, 100, 100);
@@ -6578,10 +6509,9 @@
TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShowTouches) {
// Setup the first touch screen device.
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
prepareAxes(POSITION | ID | SLOT);
addConfigurationProperty("touch.deviceType", "touchScreen");
- addMapperAndConfigure(mapper);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
// Create the second touch screen device, and enable multi fingers.
const std::string USB2 = "USB2";
@@ -6606,8 +6536,7 @@
String8("touchScreen"));
// Setup the second touch screen device.
- MultiTouchInputMapper* mapper2 = new MultiTouchInputMapper(device2.get());
- device2->addMapper(mapper2);
+ MultiTouchInputMapper& mapper2 = device2->addMapper<MultiTouchInputMapper>();
device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0 /*changes*/);
device2->reset(ARBITRARY_TIME);
@@ -6659,11 +6588,10 @@
}
TEST_F(MultiTouchInputMapperTest, VideoFrames_ReceivedByListener) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
prepareAxes(POSITION);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
- addMapperAndConfigure(mapper);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
NotifyMotionArgs motionArgs;
// Unrotated video frame
@@ -6685,10 +6613,9 @@
}
TEST_F(MultiTouchInputMapperTest, VideoFrames_AreRotated) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
prepareAxes(POSITION);
addConfigurationProperty("touch.deviceType", "touchScreen");
- addMapperAndConfigure(mapper);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
// Unrotated video frame
TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, {1, 2});
NotifyMotionArgs motionArgs;
@@ -6710,10 +6637,9 @@
}
TEST_F(MultiTouchInputMapperTest, VideoFrames_MultipleFramesAreRotated) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
prepareAxes(POSITION);
addConfigurationProperty("touch.deviceType", "touchScreen");
- addMapperAndConfigure(mapper);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
// Unrotated video frames. There's no rule that they must all have the same dimensions,
// so mix these.
TouchVideoFrame frame1(3, 2, {1, 2, 3, 4, 5, 6}, {1, 2});
@@ -6737,7 +6663,6 @@
* expected to be disabled, and it should be enabled after the viewport has found.
*/
TEST_F(MultiTouchInputMapperTest, Configure_EnabledForAssociatedDisplay) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
constexpr uint8_t hdmi2 = 1;
const std::string secondaryUniqueId = "uniqueId2";
constexpr ViewportType type = ViewportType::VIEWPORT_EXTERNAL;
@@ -6746,7 +6671,7 @@
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareAxes(POSITION);
- addMapperAndConfigure(mapper);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
ASSERT_EQ(mDevice->isEnabled(), false);
@@ -6767,11 +6692,10 @@
* Test touch should not work if outside of surface.
*/
TEST_F(MultiTouchInputMapperTest, Viewports_SurfaceRange) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION);
- addMapperAndConfigure(mapper);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
// Touch on left-top area should work.
int32_t rawX = DISPLAY_WIDTH / 2 - 1;
@@ -6783,7 +6707,7 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
// Reset.
- mapper->reset(ARBITRARY_TIME);
+ mapper.reset(ARBITRARY_TIME);
// Let logical display be different to physical display and rotate 90-degrees.
std::optional<DisplayViewport> internalViewport =
@@ -6811,11 +6735,10 @@
}
TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleSingleTouch) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION | ID | SLOT | TOOL_TYPE);
- addMapperAndConfigure(mapper);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
NotifyMotionArgs motionArgs;
@@ -6857,11 +6780,10 @@
* UP events should be ignored.
*/
TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION | ID | SLOT | TOOL_TYPE);
- addMapperAndConfigure(mapper);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
NotifyMotionArgs motionArgs;
diff --git a/services/inputflinger/tests/UinputDevice.cpp b/services/inputflinger/tests/UinputDevice.cpp
new file mode 100644
index 0000000..2775d21
--- /dev/null
+++ b/services/inputflinger/tests/UinputDevice.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "UinputDevice.h"
+
+#include <android-base/stringprintf.h>
+
+namespace android {
+
+// --- UinputDevice ---
+
+UinputDevice::UinputDevice(const char* name) : mName(name) {}
+
+UinputDevice::~UinputDevice() {
+ if (ioctl(mDeviceFd, UI_DEV_DESTROY)) {
+ ALOGE("Error while destroying uinput device: %s", strerror(errno));
+ }
+ mDeviceFd.reset();
+}
+
+void UinputDevice::init() {
+ mDeviceFd = android::base::unique_fd(open("/dev/uinput", O_WRONLY | O_NONBLOCK));
+ if (mDeviceFd < 0) {
+ FAIL() << "Can't open /dev/uinput :" << strerror(errno);
+ }
+
+ struct uinput_user_dev device = {};
+ strlcpy(device.name, mName, UINPUT_MAX_NAME_SIZE);
+ device.id.bustype = BUS_USB;
+ device.id.vendor = 0x01;
+ device.id.product = 0x01;
+ device.id.version = 1;
+
+ // Using EXPECT instead of ASSERT to allow the device creation to continue even when
+ // some failures are reported when configuring the device.
+ EXPECT_NO_FATAL_FAILURE(configureDevice(mDeviceFd, &device));
+
+ if (write(mDeviceFd, &device, sizeof(device)) < 0) {
+ FAIL() << "Could not write uinput_user_dev struct into uinput file descriptor: "
+ << strerror(errno);
+ }
+
+ if (ioctl(mDeviceFd, UI_DEV_CREATE)) {
+ FAIL() << "Error in ioctl : UI_DEV_CREATE: " << strerror(errno);
+ }
+}
+
+void UinputDevice::injectEvent(uint16_t type, uint16_t code, int32_t value) {
+ struct input_event event = {};
+ event.type = type;
+ event.code = code;
+ event.value = value;
+ event.time = {}; // uinput ignores the timestamp
+
+ if (write(mDeviceFd, &event, sizeof(input_event)) < 0) {
+ std::string msg = base::StringPrintf("Could not write event %" PRIu16 " %" PRIu16
+ " with value %" PRId32 " : %s",
+ type, code, value, strerror(errno));
+ ALOGE("%s", msg.c_str());
+ ADD_FAILURE() << msg.c_str();
+ }
+}
+
+// --- UinputKeyboard ---
+
+UinputKeyboard::UinputKeyboard(std::initializer_list<int> keys)
+ : UinputDevice(UinputKeyboard::KEYBOARD_NAME), mKeys(keys.begin(), keys.end()) {}
+
+void UinputKeyboard::configureDevice(int fd, uinput_user_dev* device) {
+ // enable key press/release event
+ if (ioctl(fd, UI_SET_EVBIT, EV_KEY)) {
+ ADD_FAILURE() << "Error in ioctl : UI_SET_EVBIT : EV_KEY: " << strerror(errno);
+ }
+
+ // enable set of KEY events
+ std::for_each(mKeys.begin(), mKeys.end(), [fd](int key) {
+ if (ioctl(fd, UI_SET_KEYBIT, key)) {
+ ADD_FAILURE() << "Error in ioctl : UI_SET_KEYBIT : " << key << " : " << strerror(errno);
+ }
+ });
+
+ // enable synchronization event
+ if (ioctl(fd, UI_SET_EVBIT, EV_SYN)) {
+ ADD_FAILURE() << "Error in ioctl : UI_SET_EVBIT : EV_SYN: " << strerror(errno);
+ }
+}
+
+void UinputKeyboard::pressKey(int key) {
+ if (mKeys.find(key) == mKeys.end()) {
+ ADD_FAILURE() << mName << ": Cannot inject key press: Key not found: " << key;
+ }
+ EXPECT_NO_FATAL_FAILURE(injectEvent(EV_KEY, key, 1));
+ EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0));
+}
+
+void UinputKeyboard::releaseKey(int key) {
+ if (mKeys.find(key) == mKeys.end()) {
+ ADD_FAILURE() << mName << ": Cannot inject key release: Key not found: " << key;
+ }
+ EXPECT_NO_FATAL_FAILURE(injectEvent(EV_KEY, key, 0));
+ EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0));
+}
+
+void UinputKeyboard::pressAndReleaseKey(int key) {
+ EXPECT_NO_FATAL_FAILURE(pressKey(key));
+ EXPECT_NO_FATAL_FAILURE(releaseKey(key));
+}
+
+// --- UinputHomeKey---
+
+UinputHomeKey::UinputHomeKey() : UinputKeyboard({KEY_HOME}) {}
+
+void UinputHomeKey::pressAndReleaseHomeKey() {
+ EXPECT_NO_FATAL_FAILURE(pressAndReleaseKey(KEY_HOME));
+}
+
+} // namespace android
diff --git a/services/inputflinger/tests/UinputDevice.h b/services/inputflinger/tests/UinputDevice.h
new file mode 100644
index 0000000..57d9011
--- /dev/null
+++ b/services/inputflinger/tests/UinputDevice.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UI_TEST_INPUT_UINPUT_INJECTOR_H
+#define _UI_TEST_INPUT_UINPUT_INJECTOR_H
+
+#include <android-base/unique_fd.h>
+#include <gtest/gtest.h>
+#include <inttypes.h>
+#include <linux/uinput.h>
+#include <log/log.h>
+
+#include <memory>
+
+namespace android {
+
+// This is the factory method that must be used to create a UinputDevice.
+template <class D, class... Ts>
+std::unique_ptr<D> createUinputDevice(Ts... args) {
+ // Using `new` to access non-public constructors.
+ std::unique_ptr<D> dev(new D(&args...));
+ EXPECT_NO_FATAL_FAILURE(dev->init());
+ return dev;
+}
+
+// --- UinputDevice ---
+
+class UinputDevice {
+public:
+ virtual ~UinputDevice();
+
+ inline const char* getName() const { return mName; }
+
+ // Subclasses must either provide a public constructor or must be-friend the factory method.
+ template <class D, class... Ts>
+ friend std::unique_ptr<D> createUinputDevice(Ts... args);
+
+protected:
+ const char* mName;
+
+ UinputDevice(const char* name);
+
+ // Signals which types of events this device supports before it is created.
+ // This must be overridden by subclasses.
+ virtual void configureDevice(int fd, uinput_user_dev* device) = 0;
+
+ void injectEvent(uint16_t type, uint16_t code, int32_t value);
+
+private:
+ base::unique_fd mDeviceFd;
+
+ // This is called once by the factory method createUinputDevice().
+ void init();
+};
+
+// --- UinputKeyboard ---
+
+class UinputKeyboard : public UinputDevice {
+public:
+ static constexpr const char* KEYBOARD_NAME = "Test Keyboard Device";
+
+ // Injects key press and sync.
+ void pressKey(int key);
+ // Injects key release and sync.
+ void releaseKey(int key);
+ // Injects 4 events: key press, sync, key release, and sync.
+ void pressAndReleaseKey(int key);
+
+ template <class D, class... Ts>
+ friend std::unique_ptr<D> createUinputDevice(Ts... args);
+
+protected:
+ UinputKeyboard(std::initializer_list<int> keys = {});
+
+private:
+ void configureDevice(int fd, uinput_user_dev* device) override;
+
+ std::set<int> mKeys;
+};
+
+// --- UinputHomeKey---
+
+// A keyboard device that has a single HOME key.
+class UinputHomeKey : public UinputKeyboard {
+public:
+ // Injects 4 events: key press, sync, key release, and sync.
+ void pressAndReleaseHomeKey();
+
+ template <class D, class... Ts>
+ friend std::unique_ptr<D> createUinputDevice(Ts... args);
+
+private:
+ UinputHomeKey();
+};
+
+} // namespace android
+
+#endif // _UI_TEST_INPUT_UINPUT_INJECTOR_H
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 914a4cb..22a15c6 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -210,12 +210,6 @@
registerSensor(new RotationVectorSensor(), !needRotationVector, true);
registerSensor(new OrientationSensor(), !needRotationVector, true);
- bool needLinearAcceleration =
- (virtualSensorsNeeds & (1<<SENSOR_TYPE_LINEAR_ACCELERATION)) != 0;
-
- registerSensor(new LinearAccelerationSensor(list, count),
- !needLinearAcceleration, true);
-
// virtual debugging sensors are not for user
registerSensor( new CorrectedGyroSensor(list, count), true, true);
registerSensor( new GyroDriftSensor(), true, true);
@@ -225,6 +219,11 @@
bool needGravitySensor = (virtualSensorsNeeds & (1<<SENSOR_TYPE_GRAVITY)) != 0;
registerSensor(new GravitySensor(list, count), !needGravitySensor, true);
+ bool needLinearAcceleration =
+ (virtualSensorsNeeds & (1<<SENSOR_TYPE_LINEAR_ACCELERATION)) != 0;
+ registerSensor(new LinearAccelerationSensor(list, count),
+ !needLinearAcceleration, true);
+
bool needGameRotationVector =
(virtualSensorsNeeds & (1<<SENSOR_TYPE_GAME_ROTATION_VECTOR)) != 0;
registerSensor(new GameRotationVectorSensor(), !needGameRotationVector, true);
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 1b1e889..4ffdf97 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -136,7 +136,7 @@
"BufferStateLayer.cpp",
"ClientCache.cpp",
"Client.cpp",
- "ColorLayer.cpp",
+ "EffectLayer.cpp",
"ContainerLayer.cpp",
"DisplayDevice.cpp",
"DisplayHardware/ComposerHal.cpp",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index f4f45be..5a955f7 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -180,95 +180,91 @@
}
bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) ||
(isSecure() && !targetSettings.isSecure);
- const State& s(getDrawingState());
compositionengine::LayerFE::LayerSettings& layer = *result;
- if (!blackOutLayer) {
- layer.source.buffer.buffer = mBufferInfo.mBuffer;
- layer.source.buffer.isOpaque = isOpaque(s);
- layer.source.buffer.fence = mBufferInfo.mFence;
- layer.source.buffer.textureName = mTextureName;
- layer.source.buffer.usePremultipliedAlpha = getPremultipledAlpha();
- layer.source.buffer.isY410BT2020 = isHdrY410();
- bool hasSmpte2086 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::SMPTE2086;
- bool hasCta861_3 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::CTA861_3;
- layer.source.buffer.maxMasteringLuminance = hasSmpte2086
- ? mBufferInfo.mHdrMetadata.smpte2086.maxLuminance
- : defaultMaxMasteringLuminance;
- layer.source.buffer.maxContentLuminance = hasCta861_3
- ? mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel
- : defaultMaxContentLuminance;
- layer.frameNumber = mCurrentFrameNumber;
- layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0;
-
- // TODO: we could be more subtle with isFixedSize()
- const bool useFiltering = targetSettings.needsFiltering || mNeedsFiltering || isFixedSize();
-
- // Query the texture matrix given our current filtering mode.
- float textureMatrix[16];
- getDrawingTransformMatrix(useFiltering, textureMatrix);
-
- if (getTransformToDisplayInverse()) {
- /*
- * the code below applies the primary display's inverse transform to
- * the texture transform
- */
- uint32_t transform = DisplayDevice::getPrimaryDisplayRotationFlags();
- mat4 tr = inverseOrientation(transform);
-
- /**
- * TODO(b/36727915): This is basically a hack.
- *
- * Ensure that regardless of the parent transformation,
- * this buffer is always transformed from native display
- * orientation to display orientation. For example, in the case
- * of a camera where the buffer remains in native orientation,
- * we want the pixels to always be upright.
- */
- sp<Layer> p = mDrawingParent.promote();
- if (p != nullptr) {
- const auto parentTransform = p->getTransform();
- tr = tr * inverseOrientation(parentTransform.getOrientation());
- }
-
- // and finally apply it to the original texture matrix
- const mat4 texTransform(mat4(static_cast<const float*>(textureMatrix)) * tr);
- memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix));
- }
-
- const Rect win{getBounds()};
- float bufferWidth = getBufferSize(s).getWidth();
- float bufferHeight = getBufferSize(s).getHeight();
-
- // BufferStateLayers can have a "buffer size" of [0, 0, -1, -1] when no display frame has
- // been set and there is no parent layer bounds. In that case, the scale is meaningless so
- // ignore them.
- if (!getBufferSize(s).isValid()) {
- bufferWidth = float(win.right) - float(win.left);
- bufferHeight = float(win.bottom) - float(win.top);
- }
-
- const float scaleHeight = (float(win.bottom) - float(win.top)) / bufferHeight;
- const float scaleWidth = (float(win.right) - float(win.left)) / bufferWidth;
- const float translateY = float(win.top) / bufferHeight;
- const float translateX = float(win.left) / bufferWidth;
-
- // Flip y-coordinates because GLConsumer expects OpenGL convention.
- mat4 tr = mat4::translate(vec4(.5, .5, 0, 1)) * mat4::scale(vec4(1, -1, 1, 1)) *
- mat4::translate(vec4(-.5, -.5, 0, 1)) *
- mat4::translate(vec4(translateX, translateY, 0, 1)) *
- mat4::scale(vec4(scaleWidth, scaleHeight, 1.0, 1.0));
-
- layer.source.buffer.useTextureFiltering = useFiltering;
- layer.source.buffer.textureTransform = mat4(static_cast<const float*>(textureMatrix)) * tr;
- } else {
- // If layer is blacked out, force alpha to 1 so that we draw a black color
- // layer.
- layer.source.buffer.buffer = nullptr;
- layer.alpha = 1.0;
- layer.frameNumber = 0;
- layer.bufferId = 0;
+ if (blackOutLayer) {
+ prepareClearClientComposition(layer, true /* blackout */);
+ return layer;
}
+ const State& s(getDrawingState());
+ layer.source.buffer.buffer = mBufferInfo.mBuffer;
+ layer.source.buffer.isOpaque = isOpaque(s);
+ layer.source.buffer.fence = mBufferInfo.mFence;
+ layer.source.buffer.textureName = mTextureName;
+ layer.source.buffer.usePremultipliedAlpha = getPremultipledAlpha();
+ layer.source.buffer.isY410BT2020 = isHdrY410();
+ bool hasSmpte2086 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::SMPTE2086;
+ bool hasCta861_3 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::CTA861_3;
+ layer.source.buffer.maxMasteringLuminance = hasSmpte2086
+ ? mBufferInfo.mHdrMetadata.smpte2086.maxLuminance
+ : defaultMaxMasteringLuminance;
+ layer.source.buffer.maxContentLuminance = hasCta861_3
+ ? mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel
+ : defaultMaxContentLuminance;
+ layer.frameNumber = mCurrentFrameNumber;
+ layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0;
+
+ // TODO: we could be more subtle with isFixedSize()
+ const bool useFiltering = targetSettings.needsFiltering || mNeedsFiltering || isFixedSize();
+
+ // Query the texture matrix given our current filtering mode.
+ float textureMatrix[16];
+ getDrawingTransformMatrix(useFiltering, textureMatrix);
+
+ if (getTransformToDisplayInverse()) {
+ /*
+ * the code below applies the primary display's inverse transform to
+ * the texture transform
+ */
+ uint32_t transform = DisplayDevice::getPrimaryDisplayRotationFlags();
+ mat4 tr = inverseOrientation(transform);
+
+ /**
+ * TODO(b/36727915): This is basically a hack.
+ *
+ * Ensure that regardless of the parent transformation,
+ * this buffer is always transformed from native display
+ * orientation to display orientation. For example, in the case
+ * of a camera where the buffer remains in native orientation,
+ * we want the pixels to always be upright.
+ */
+ sp<Layer> p = mDrawingParent.promote();
+ if (p != nullptr) {
+ const auto parentTransform = p->getTransform();
+ tr = tr * inverseOrientation(parentTransform.getOrientation());
+ }
+
+ // and finally apply it to the original texture matrix
+ const mat4 texTransform(mat4(static_cast<const float*>(textureMatrix)) * tr);
+ memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix));
+ }
+
+ const Rect win{getBounds()};
+ float bufferWidth = getBufferSize(s).getWidth();
+ float bufferHeight = getBufferSize(s).getHeight();
+
+ // BufferStateLayers can have a "buffer size" of [0, 0, -1, -1] when no display frame has
+ // been set and there is no parent layer bounds. In that case, the scale is meaningless so
+ // ignore them.
+ if (!getBufferSize(s).isValid()) {
+ bufferWidth = float(win.right) - float(win.left);
+ bufferHeight = float(win.bottom) - float(win.top);
+ }
+
+ const float scaleHeight = (float(win.bottom) - float(win.top)) / bufferHeight;
+ const float scaleWidth = (float(win.right) - float(win.left)) / bufferWidth;
+ const float translateY = float(win.top) / bufferHeight;
+ const float translateX = float(win.left) / bufferWidth;
+
+ // Flip y-coordinates because GLConsumer expects OpenGL convention.
+ mat4 tr = mat4::translate(vec4(.5, .5, 0, 1)) * mat4::scale(vec4(1, -1, 1, 1)) *
+ mat4::translate(vec4(-.5, -.5, 0, 1)) *
+ mat4::translate(vec4(translateX, translateY, 0, 1)) *
+ mat4::scale(vec4(scaleWidth, scaleHeight, 1.0, 1.0));
+
+ layer.source.buffer.useTextureFiltering = useFiltering;
+ layer.source.buffer.textureTransform = mat4(static_cast<const float*>(textureMatrix)) * tr;
+
return layer;
}
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 4085b52..f678910 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -173,14 +173,15 @@
BufferInfo mBufferInfo;
virtual void gatherBufferInfo() = 0;
+ std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
+ compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
+
/*
* compositionengine::LayerFE overrides
*/
const compositionengine::LayerFECompositionState* getCompositionState() const override;
bool onPreComposition(nsecs_t) override;
void preparePerFrameCompositionState() override;
- std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
- compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
// Loads the corresponding system property once per process
static bool latchUnsignaledBuffers();
@@ -202,12 +203,12 @@
void updateCloneBufferInfo() override;
uint64_t mPreviousFrameNumber = 0;
+ virtual uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const;
+
private:
// Returns true if this layer requires filtering
bool needsFiltering(const sp<const DisplayDevice>& displayDevice) const override;
- uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const;
-
// BufferStateLayers can return Rect::INVALID_RECT if the layer does not have a display frame
// and its parent layer is not bounded
Rect getBufferSize(const State& s) const override;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 371b802..de5429b 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -32,7 +32,7 @@
#include <private/gui/SyncFeatures.h>
#include <renderengine/Image.h>
-#include "ColorLayer.h"
+#include "EffectLayer.h"
#include "FrameTracer/FrameTracer.h"
#include "TimeStats/TimeStats.h"
@@ -468,6 +468,32 @@
return mDrawingState.frameNumber;
}
+/**
+ * This is the frameNumber used for deferred transaction signalling. We need to use this because
+ * of cases where we defer a transaction for a surface to itself. In the BLAST world this
+ * may not make a huge amount of sense (Why not just merge the Buffer transaction with the
+ * deferred transaction?) but this is an important legacy use case, for example moving
+ * a window at the same time it draws makes use of this kind of technique. So anyway
+ * imagine we have something like this:
+ *
+ * Transaction { // containing
+ * Buffer -> frameNumber = 2
+ * DeferTransactionUntil -> frameNumber = 2
+ * Random other stuff
+ * }
+ * Now imagine getHeadFrameNumber returned mDrawingState.mFrameNumber (or mCurrentFrameNumber).
+ * Prior to doTransaction SurfaceFlinger will call notifyAvailableFrames, but because we
+ * haven't swapped mCurrentState to mDrawingState yet we will think the sync point
+ * is not ready. So we will return false from applyPendingState and not swap
+ * current state to drawing state. But because we don't swap current state
+ * to drawing state the number will never update and we will be stuck. This way
+ * we can see we need to return the frame number for the buffer we are about
+ * to apply.
+ */
+uint64_t BufferStateLayer::getHeadFrameNumber(nsecs_t /* expectedPresentTime */) const {
+ return mCurrentState.frameNumber;
+}
+
bool BufferStateLayer::getAutoRefresh() const {
// TODO(marissaw): support shared buffer mode
return false;
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 539442a..753a742 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -116,6 +116,7 @@
protected:
void gatherBufferInfo() override;
+ uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const;
private:
bool updateFrameEventHistory(const sp<Fence>& acquireFence, nsecs_t postedTime,
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
deleted file mode 100644
index 83050c4..0000000
--- a/services/surfaceflinger/ColorLayer.cpp
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-
-// #define LOG_NDEBUG 0
-#undef LOG_TAG
-#define LOG_TAG "ColorLayer"
-
-#include "ColorLayer.h"
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <sys/types.h>
-
-#include <compositionengine/CompositionEngine.h>
-#include <compositionengine/LayerFECompositionState.h>
-#include <renderengine/RenderEngine.h>
-#include <ui/GraphicBuffer.h>
-#include <utils/Errors.h>
-#include <utils/Log.h>
-
-#include "DisplayDevice.h"
-#include "SurfaceFlinger.h"
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-ColorLayer::ColorLayer(const LayerCreationArgs& args)
- : Layer(args),
- mCompositionState{mFlinger->getCompositionEngine().createLayerFECompositionState()} {}
-
-ColorLayer::~ColorLayer() = default;
-
-std::optional<compositionengine::LayerFE::LayerSettings> ColorLayer::prepareClientComposition(
- compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
- auto result = Layer::prepareClientComposition(targetSettings);
- if (!result) {
- return result;
- }
- result->source.solidColor = getColor().rgb;
- return result;
-}
-
-bool ColorLayer::isVisible() const {
- return !isHiddenByPolicy() && getAlpha() > 0.0_hf;
-}
-
-bool ColorLayer::setColor(const half3& color) {
- if (mCurrentState.color.r == color.r && mCurrentState.color.g == color.g &&
- mCurrentState.color.b == color.b) {
- return false;
- }
-
- mCurrentState.sequence++;
- mCurrentState.color.r = color.r;
- mCurrentState.color.g = color.g;
- mCurrentState.color.b = color.b;
- mCurrentState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool ColorLayer::setDataspace(ui::Dataspace dataspace) {
- if (mCurrentState.dataspace == dataspace) {
- return false;
- }
-
- mCurrentState.sequence++;
- mCurrentState.dataspace = dataspace;
- mCurrentState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-void ColorLayer::preparePerFrameCompositionState() {
- Layer::preparePerFrameCompositionState();
-
- auto* compositionState = editCompositionState();
- compositionState->color = getColor();
- compositionState->compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
-}
-
-sp<compositionengine::LayerFE> ColorLayer::getCompositionEngineLayerFE() const {
- return asLayerFE();
-}
-
-compositionengine::LayerFECompositionState* ColorLayer::editCompositionState() {
- return mCompositionState.get();
-}
-
-const compositionengine::LayerFECompositionState* ColorLayer::getCompositionState() const {
- return mCompositionState.get();
-}
-
-bool ColorLayer::isOpaque(const Layer::State& s) const {
- // Consider the layer to be opaque if its opaque flag is set or its effective
- // alpha (considering the alpha of its parents as well) is 1.0;
- return (s.flags & layer_state_t::eLayerOpaque) != 0 || getAlpha() == 1.0_hf;
-}
-
-ui::Dataspace ColorLayer::getDataSpace() const {
- return mDrawingState.dataspace;
-}
-
-sp<Layer> ColorLayer::createClone() {
- sp<ColorLayer> layer = mFlinger->getFactory().createColorLayer(
- LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0,
- LayerMetadata()));
- layer->setInitialValuesForClone(this);
- return layer;
-}
-
-} // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index 912dffd..6cc90cb 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -97,6 +97,21 @@
// Modified by each call to prepareClientComposition to indicate the
// region of the target buffer that should be cleared.
Region& clearRegion;
+
+ // Viewport of the target being rendered to. This is used to determine
+ // the shadow light position.
+ const Rect& viewport;
+
+ // Dataspace of the output so we can optimize how to render the shadow
+ // by avoiding unnecessary color space conversions.
+ const ui::Dataspace dataspace;
+
+ // True if the region excluding the shadow is visible.
+ const bool realContentIsVisible;
+
+ // If set to true, change the layer settings to render a clear output.
+ // This may be requested by the HWC
+ const bool clearContent;
};
// A superset of LayerSettings required by RenderEngine to compose a layer
@@ -109,18 +124,12 @@
uint64_t frameNumber = 0;
};
- // Returns the LayerSettings to pass to RenderEngine::drawLayers, or
- // nullopt_t if the layer does not render
- virtual std::optional<LayerSettings> prepareClientComposition(
+ // Returns the z-ordered list of LayerSettings to pass to RenderEngine::drawLayers. The list
+ // may contain shadows casted by the layer or the content of the layer itself. If the layer
+ // does not render then an empty list will be returned.
+ virtual std::vector<LayerSettings> prepareClientCompositionList(
ClientCompositionTargetSettings&) = 0;
- // Returns the LayerSettings used to draw shadows around a layer. It is passed
- // to RenderEngine::drawLayers. Returns nullopt_t if the layer does not render
- // shadows.
- virtual std::optional<LayerSettings> prepareShadowClientComposition(
- const LayerSettings& layerSettings, const Rect& displayViewport,
- ui::Dataspace outputDataspace) = 0;
-
// Called after the layer is displayed to update the presentation fence
virtual void onLayerDisplayed(const sp<Fence>&) = 0;
@@ -142,7 +151,10 @@
lhs.useIdentityTransform == rhs.useIdentityTransform &&
lhs.needsFiltering == rhs.needsFiltering && lhs.isSecure == rhs.isSecure &&
lhs.supportsProtectedContent == rhs.supportsProtectedContent &&
- lhs.clearRegion.hasSameRects(rhs.clearRegion);
+ lhs.clearRegion.hasSameRects(rhs.clearRegion) && lhs.viewport == rhs.viewport &&
+ lhs.dataspace == rhs.dataspace &&
+ lhs.realContentIsVisible == rhs.realContentIsVisible &&
+ lhs.clearContent == rhs.clearContent;
}
static inline bool operator==(const LayerFE::LayerSettings& lhs,
@@ -164,6 +176,12 @@
*os << "\n .supportsProtectedContent = " << settings.supportsProtectedContent;
*os << "\n .clearRegion = ";
PrintTo(settings.clearRegion, os);
+ *os << "\n .viewport = ";
+ PrintTo(settings.viewport, os);
+ *os << "\n .dataspace = ";
+ PrintTo(settings.dataspace, os);
+ *os << "\n .realContentIsVisible = " << settings.realContentIsVisible;
+ *os << "\n .clearContent = " << settings.clearContent;
*os << "\n}";
}
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index 40cd3e0..d8ce629 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -40,6 +40,29 @@
namespace android::compositionengine {
+// More complex metadata for this layer
+struct GenericLayerMetadataEntry {
+ // True if the metadata may affect the composed result.
+ // See setLayerGenericMetadata in IComposerClient.hal
+ bool mandatory;
+
+ // Byte blob or parcel
+ std::vector<uint8_t> value;
+
+ std::string dumpAsString() const;
+};
+
+inline bool operator==(const GenericLayerMetadataEntry& lhs, const GenericLayerMetadataEntry& rhs) {
+ return lhs.mandatory == rhs.mandatory && lhs.value == rhs.value;
+}
+
+// Defining PrintTo helps with Google Tests.
+inline void PrintTo(const GenericLayerMetadataEntry& v, ::std::ostream* os) {
+ *os << v.dumpAsString();
+}
+
+using GenericLayerMetadataMap = std::unordered_map<std::string, GenericLayerMetadataEntry>;
+
/*
* Used by LayerFE::getCompositionState
*/
@@ -115,6 +138,8 @@
// The appId for this layer
int appId{0};
+ GenericLayerMetadataMap metadata;
+
/*
* Per-frame content
*/
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index 5c2ad15..45891a7 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -35,11 +35,9 @@
MOCK_METHOD1(onPreComposition, bool(nsecs_t));
MOCK_METHOD1(prepareCompositionState, void(compositionengine::LayerFE::StateSubset));
- MOCK_METHOD1(prepareClientComposition,
- std::optional<LayerSettings>(
+ MOCK_METHOD1(prepareClientCompositionList,
+ std::vector<compositionengine::LayerFE::LayerSettings>(
compositionengine::LayerFE::ClientCompositionTargetSettings&));
- MOCK_METHOD3(prepareShadowClientComposition,
- std::optional<LayerSettings>(const LayerSettings&, const Rect&, ui::Dataspace));
MOCK_METHOD1(onLayerDisplayed, void(const sp<Fence>&));
diff --git a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
index 3e0f803..02e3a45 100644
--- a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
@@ -32,6 +32,20 @@
} // namespace
+std::string GenericLayerMetadataEntry::dumpAsString() const {
+ using android::base::StringAppendF;
+ std::string out;
+
+ out.append("GenericLayerMetadataEntry{mandatory: ");
+ StringAppendF(&out, "%d", mandatory);
+ out.append(" value: ");
+ for (uint8_t byte : value) {
+ StringAppendF(&out, "0x08%" PRIx8 " ", byte);
+ }
+ out.append("]}");
+ return out;
+}
+
LayerFECompositionState::~LayerFECompositionState() = default;
void LayerFECompositionState::dump(std::string& out) const {
@@ -65,6 +79,17 @@
dumpVal(out, "type", type);
dumpVal(out, "appId", appId);
+ if (!metadata.empty()) {
+ out.append("\n metadata {");
+ for (const auto& [key, entry] : metadata) {
+ out.append("\n ");
+ out.append(key);
+ out.append("=");
+ out.append(entry.dumpAsString());
+ }
+ out.append("\n }\n ");
+ }
+
dumpVal(out, "composition type", toString(compositionType), compositionType);
out.append("\n buffer: ");
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index a389bf3..e792f45 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -963,11 +963,16 @@
// rectangle, as by definition the layer must blend with whatever is
// underneath. We also skip the first layer as the buffer target is
// guaranteed to start out cleared.
- bool clearClientComposition =
+ const bool clearClientComposition =
layerState.clearClientTarget && layerFEState->isOpaque && !firstLayer;
ALOGV(" Composition type: client %d clear %d", clientComposition, clearClientComposition);
+ // If the layer casts a shadow but the content casting the shadow is occluded, skip
+ // composing the non-shadow content and only draw the shadows.
+ const bool realContentIsVisible = clientComposition &&
+ !layerState.visibleRegion.subtract(layerState.shadowRegion).isEmpty();
+
if (clientComposition || clearClientComposition) {
compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
clip,
@@ -976,35 +981,21 @@
outputState.isSecure,
supportsProtectedContent,
clientComposition ? clearRegion : dummyRegion,
+ outputState.viewport,
+ outputDataspace,
+ realContentIsVisible,
+ !clientComposition, /* clearContent */
};
- if (std::optional<LayerFE::LayerSettings> result =
- layerFE.prepareClientComposition(targetSettings)) {
- if (!clientComposition) {
- LayerFE::LayerSettings& layerSettings = *result;
- layerSettings.source.buffer.buffer = nullptr;
- layerSettings.source.solidColor = half3(0.0, 0.0, 0.0);
- layerSettings.alpha = half(0.0);
- layerSettings.disableBlending = true;
- layerSettings.frameNumber = 0;
- } else {
- std::optional<LayerFE::LayerSettings> shadowLayer =
- layerFE.prepareShadowClientComposition(*result, outputState.viewport,
- outputDataspace);
- if (shadowLayer) {
- clientCompositionLayers.push_back(*shadowLayer);
- }
- }
-
- // If the layer casts a shadow but the content casting the shadow is occluded, skip
- // composing the non-shadow content and only draw the shadows.
- const bool skipNonShadowContentComposition = clientComposition &&
- layerState.visibleRegion.subtract(layerState.shadowRegion).isEmpty();
-
- if (!skipNonShadowContentComposition) {
- layer->editState().clientCompositionTimestamp = systemTime();
- clientCompositionLayers.push_back(*result);
- }
+ std::vector<LayerFE::LayerSettings> results =
+ layerFE.prepareClientCompositionList(targetSettings);
+ if (realContentIsVisible && !results.empty()) {
+ layer->editState().clientCompositionTimestamp = systemTime();
}
+
+ clientCompositionLayers.insert(clientCompositionLayers.end(),
+ std::make_move_iterator(results.begin()),
+ std::make_move_iterator(results.end()));
+ results.clear();
}
firstLayer = false;
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index b538d75..3aa7956 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -406,6 +406,14 @@
ALOGE("[%s] Failed to set info %s (%d)", getLayerFE().getDebugName(),
to_string(error).c_str(), static_cast<int32_t>(error));
}
+
+ for (const auto& [name, entry] : outputIndependentState.metadata) {
+ if (auto error = hwcLayer->setLayerGenericMetadata(name, entry.mandatory, entry.value);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set generic metadata %s %s (%d)", getLayerFE().getDebugName(),
+ name.c_str(), to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+ }
}
void OutputLayer::writeOutputDependentPerFrameStateToHWC(HWC2::Layer* hwcLayer) {
@@ -661,4 +669,3 @@
} // namespace impl
} // namespace android::compositionengine
-
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
index a51cc67..be89c1a 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
@@ -65,6 +65,8 @@
MOCK_METHOD2(setInfo, Error(uint32_t, uint32_t));
MOCK_METHOD1(setColorTransform, Error(const android::mat4&));
+ MOCK_METHOD3(setLayerGenericMetadata,
+ Error(const std::string&, bool, const std::vector<uint8_t>&));
};
} // namespace mock
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 502a33f..02226ab 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -36,7 +36,7 @@
HWComposer();
~HWComposer() override;
- MOCK_METHOD2(registerCallback, void(HWC2::ComposerCallback*, int32_t));
+ MOCK_METHOD2(setConfiguration, void(HWC2::ComposerCallback*, int32_t));
MOCK_CONST_METHOD3(getDisplayIdentificationData,
bool(hwc2_display_t, uint8_t*, DisplayIdentificationData*));
MOCK_CONST_METHOD1(hasCapability, bool(HWC2::Capability));
@@ -88,6 +88,7 @@
MOCK_CONST_METHOD1(getColorModes, std::vector<ui::ColorMode>(DisplayId));
MOCK_METHOD3(setActiveColorMode, status_t(DisplayId, ui::ColorMode, ui::RenderIntent));
MOCK_CONST_METHOD0(isUsingVrComposer, bool());
+ MOCK_CONST_METHOD1(getDisplayConnectionType, DisplayConnectionType(DisplayId));
MOCK_CONST_METHOD1(isVsyncPeriodSwitchSupported, bool(DisplayId));
MOCK_CONST_METHOD1(getDisplayVsyncPeriod, nsecs_t(DisplayId));
MOCK_METHOD4(setActiveConfigWithConstraints,
@@ -96,6 +97,8 @@
MOCK_METHOD2(setAutoLowLatencyMode, status_t(DisplayId, bool));
MOCK_METHOD2(getSupportedContentTypes, status_t(DisplayId, std::vector<HWC2::ContentType>*));
MOCK_METHOD2(setContentType, status_t(DisplayId, HWC2::ContentType));
+ MOCK_CONST_METHOD0(getSupportedLayerGenericMetadata,
+ const std::unordered_map<std::string, bool>&());
MOCK_CONST_METHOD1(dump, void(std::string&));
MOCK_CONST_METHOD0(getComposer, android::Hwc2::Composer*());
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 963062f..1b5617c 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -625,6 +625,8 @@
static constexpr ui::Dataspace kDataspace = static_cast<ui::Dataspace>(71);
static constexpr int kSupportedPerFrameMetadata = 101;
static constexpr int kExpectedHwcSlot = 0;
+ static constexpr bool kLayerGenericMetadata1Mandatory = true;
+ static constexpr bool kLayerGenericMetadata2Mandatory = true;
static const half4 kColor;
static const Rect kDisplayFrame;
@@ -635,6 +637,10 @@
static native_handle_t* kSidebandStreamHandle;
static const sp<GraphicBuffer> kBuffer;
static const sp<Fence> kFence;
+ static const std::string kLayerGenericMetadata1Key;
+ static const std::vector<uint8_t> kLayerGenericMetadata1Value;
+ static const std::string kLayerGenericMetadata2Key;
+ static const std::vector<uint8_t> kLayerGenericMetadata2Value;
OutputLayerWriteStateToHWCTest() {
auto& outputLayerState = mOutputLayer.editState();
@@ -669,6 +675,13 @@
// Some tests may need to simulate unsupported HWC calls
enum class SimulateUnsupported { None, ColorTransform };
+ void includeGenericLayerMetadataInState() {
+ mLayerFEState.metadata[kLayerGenericMetadata1Key] = {kLayerGenericMetadata1Mandatory,
+ kLayerGenericMetadata1Value};
+ mLayerFEState.metadata[kLayerGenericMetadata2Key] = {kLayerGenericMetadata2Mandatory,
+ kLayerGenericMetadata2Value};
+ }
+
void expectGeometryCommonCalls() {
EXPECT_CALL(*mHwcLayer, setDisplayFrame(kDisplayFrame)).WillOnce(Return(kError));
EXPECT_CALL(*mHwcLayer, setSourceCrop(kSourceCrop)).WillOnce(Return(kError));
@@ -720,6 +733,18 @@
EXPECT_CALL(*mHwcLayer, setBuffer(kExpectedHwcSlot, kBuffer, kFence));
}
+ void expectGenericLayerMetadataCalls() {
+ // Note: Can be in any order.
+ EXPECT_CALL(*mHwcLayer,
+ setLayerGenericMetadata(kLayerGenericMetadata1Key,
+ kLayerGenericMetadata1Mandatory,
+ kLayerGenericMetadata1Value));
+ EXPECT_CALL(*mHwcLayer,
+ setLayerGenericMetadata(kLayerGenericMetadata2Key,
+ kLayerGenericMetadata2Mandatory,
+ kLayerGenericMetadata2Value));
+ }
+
std::shared_ptr<HWC2::mock::Layer> mHwcLayer{std::make_shared<StrictMock<HWC2::mock::Layer>>()};
StrictMock<mock::DisplayColorProfile> mDisplayColorProfile;
};
@@ -739,6 +764,13 @@
reinterpret_cast<native_handle_t*>(1031);
const sp<GraphicBuffer> OutputLayerWriteStateToHWCTest::kBuffer;
const sp<Fence> OutputLayerWriteStateToHWCTest::kFence;
+const std::string OutputLayerWriteStateToHWCTest::kLayerGenericMetadata1Key =
+ "com.example.metadata.1";
+const std::vector<uint8_t> OutputLayerWriteStateToHWCTest::kLayerGenericMetadata1Value{{1, 2, 3}};
+const std::string OutputLayerWriteStateToHWCTest::kLayerGenericMetadata2Key =
+ "com.example.metadata.2";
+const std::vector<uint8_t> OutputLayerWriteStateToHWCTest::kLayerGenericMetadata2Value{
+ {4, 5, 6, 7}};
TEST_F(OutputLayerWriteStateToHWCTest, doesNothingIfNoFECompositionState) {
EXPECT_CALL(*mLayerFE, getCompositionState()).WillOnce(Return(nullptr));
@@ -862,6 +894,30 @@
mOutputLayer.writeStateToHWC(false);
}
+TEST_F(OutputLayerWriteStateToHWCTest, allStateIncludesMetadataIfPresent) {
+ mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE;
+ includeGenericLayerMetadataInState();
+
+ expectGeometryCommonCalls();
+ expectPerFrameCommonCalls();
+ expectSetHdrMetadataAndBufferCalls();
+ expectGenericLayerMetadataCalls();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
+
+ mOutputLayer.writeStateToHWC(true);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, perFrameStateDoesNotIncludeMetadataIfPresent) {
+ mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE;
+ includeGenericLayerMetadataInState();
+
+ expectPerFrameCommonCalls();
+ expectSetHdrMetadataAndBufferCalls();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
+
+ mOutputLayer.writeStateToHWC(false);
+}
+
/*
* OutputLayer::writeCursorPositionToHWC()
*/
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 2b45046..be0e9e4 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -3425,19 +3425,13 @@
LayerFE::LayerSettings mShadowSettings;
mShadowSettings.source.solidColor = {0.1f, 0.1f, 0.1f};
- EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(_)).WillOnce(Return(std::nullopt));
- EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[1].mLayerSettings));
- EXPECT_CALL(mLayers[1].mLayerFE,
- prepareShadowClientComposition(mLayers[1].mLayerSettings, kDisplayViewport,
- kDisplayDataspace))
- .WillOnce(Return(std::nullopt));
- EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[2].mLayerSettings));
- EXPECT_CALL(mLayers[2].mLayerFE,
- prepareShadowClientComposition(mLayers[2].mLayerSettings, kDisplayViewport,
- kDisplayDataspace))
- .WillOnce(Return(mShadowSettings));
+ EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(_))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+ EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(_))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mLayers[1].mLayerSettings})));
+ EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(_))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>(
+ {mShadowSettings, mLayers[2].mLayerSettings})));
Region accumClearRegion(Rect(10, 11, 12, 13));
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
@@ -3469,10 +3463,8 @@
mLayers[1].mLayerFEState.isOpaque = true;
mLayers[2].mLayerFEState.isOpaque = true;
- EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[2].mLayerSettings));
- EXPECT_CALL(mLayers[2].mLayerFE, prepareShadowClientComposition(_, _, _))
- .WillOnce(Return(std::nullopt));
+ EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(_))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mLayers[2].mLayerSettings})));
Region accumClearRegion(Rect(10, 11, 12, 13));
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
@@ -3497,10 +3489,8 @@
mLayers[1].mLayerFEState.isOpaque = false;
mLayers[2].mLayerFEState.isOpaque = false;
- EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[2].mLayerSettings));
- EXPECT_CALL(mLayers[2].mLayerFE, prepareShadowClientComposition(_, _, _))
- .WillOnce(Return(std::nullopt));
+ EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(_))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mLayers[2].mLayerSettings})));
Region accumClearRegion(Rect(10, 11, 12, 13));
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
@@ -3529,25 +3519,51 @@
mLayers[0].mLayerFEState.isOpaque = true;
mLayers[1].mLayerFEState.isOpaque = true;
mLayers[2].mLayerFEState.isOpaque = true;
-
- EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[1].mLayerSettings));
- EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[2].mLayerSettings));
- EXPECT_CALL(mLayers[2].mLayerFE, prepareShadowClientComposition(_, _, _))
- .WillOnce(Return(std::nullopt));
-
Region accumClearRegion(Rect(10, 11, 12, 13));
+ Region dummyRegion;
+
+ compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
+ Region(kDisplayFrame),
+ false, /* identity transform */
+ false, /* needs filtering */
+ false, /* secure */
+ false, /* supports protected content */
+ dummyRegion, /* clear region */
+ kDisplayViewport,
+ kDisplayDataspace,
+ false /* realContentIsVisible */,
+ true /* clearContent */,
+ };
+ compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
+ Region(kDisplayFrame),
+ false, /* identity transform */
+ false, /* needs filtering */
+ false, /* secure */
+ false, /* supports protected content */
+ accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
+ };
+
+ LayerFE::LayerSettings mBlackoutSettings = mLayers[1].mLayerSettings;
+ mBlackoutSettings.source.buffer.buffer = nullptr;
+ mBlackoutSettings.source.solidColor = {0.1f, 0.1f, 0.1f};
+ mBlackoutSettings.alpha = 0.f;
+ mBlackoutSettings.disableBlending = true;
+
+ EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mBlackoutSettings})));
+ EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mLayers[2].mLayerSettings})));
+
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
accumClearRegion, kDisplayDataspace);
ASSERT_EQ(2u, requests.size());
// The second layer is expected to be rendered as alpha=0 black with no blending
- EXPECT_EQ(mLayers[1].mLayerSettings.geometry.boundaries, requests[0].geometry.boundaries);
- EXPECT_FALSE(requests[0].source.buffer.buffer);
- EXPECT_EQ((half3{0.f, 0.f, 0.f}), requests[0].source.solidColor);
- EXPECT_EQ(0.f, static_cast<float>(requests[0].alpha));
- EXPECT_EQ(true, requests[0].disableBlending);
+ EXPECT_EQ(mBlackoutSettings, requests[0]);
EXPECT_EQ(mLayers[2].mLayerSettings, requests[1]);
@@ -3569,6 +3585,10 @@
false, /* secure */
false, /* supports protected content */
accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
Region(Rect(0, 0, 30, 30)),
@@ -3577,6 +3597,10 @@
false, /* secure */
false, /* supports protected content */
accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
Region(Rect(0, 0, 40, 201)),
@@ -3585,14 +3609,18 @@
false, /* secure */
false, /* supports protected content */
accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
- EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings))))
- .WillOnce(Return(std::nullopt));
- EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings))))
- .WillOnce(Return(std::nullopt));
- EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings))))
- .WillOnce(Return(std::nullopt));
+ EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+ EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+ EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
static_cast<void>(
mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
@@ -3613,6 +3641,10 @@
false, /* secure */
false, /* supports protected content */
accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
Region(kDisplayFrame),
@@ -3621,6 +3653,10 @@
false, /* secure */
false, /* supports protected content */
accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
Region(kDisplayFrame),
@@ -3629,14 +3665,18 @@
false, /* secure */
false, /* supports protected content */
accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
- EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings))))
- .WillOnce(Return(std::nullopt));
- EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings))))
- .WillOnce(Return(std::nullopt));
- EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings))))
- .WillOnce(Return(std::nullopt));
+ EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+ EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+ EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
static_cast<void>(
mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
@@ -3657,6 +3697,11 @@
false, /* secure */
false, /* supports protected content */
accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
+
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
Region(kDisplayFrame),
@@ -3665,6 +3710,10 @@
false, /* secure */
false, /* supports protected content */
accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
Region(kDisplayFrame),
@@ -3673,14 +3722,18 @@
false, /* secure */
false, /* supports protected content */
accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
- EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings))))
- .WillOnce(Return(std::nullopt));
- EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings))))
- .WillOnce(Return(std::nullopt));
- EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings))))
- .WillOnce(Return(std::nullopt));
+ EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+ EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+ EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
static_cast<void>(
mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
@@ -3700,6 +3753,10 @@
true, /* secure */
false, /* supports protected content */
accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
Region(kDisplayFrame),
@@ -3708,6 +3765,10 @@
true, /* secure */
false, /* supports protected content */
accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
Region(kDisplayFrame),
@@ -3716,14 +3777,18 @@
true, /* secure */
false, /* supports protected content */
accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
- EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings))))
- .WillOnce(Return(std::nullopt));
- EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings))))
- .WillOnce(Return(std::nullopt));
- EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings))))
- .WillOnce(Return(std::nullopt));
+ EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+ EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+ EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
static_cast<void>(
mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
@@ -3741,6 +3806,10 @@
false, /* secure */
true, /* supports protected content */
accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
Region(kDisplayFrame),
@@ -3749,6 +3818,10 @@
false, /* secure */
true, /* supports protected content */
accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
Region(kDisplayFrame),
@@ -3757,14 +3830,18 @@
false, /* secure */
true, /* supports protected content */
accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
- EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings))))
- .WillOnce(Return(std::nullopt));
- EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings))))
- .WillOnce(Return(std::nullopt));
- EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings))))
- .WillOnce(Return(std::nullopt));
+ EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+ EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+ EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
static_cast<void>(mOutput.generateClientCompositionRequests(true /* supportsProtectedContent */,
accumClearRegion,
@@ -3847,16 +3924,16 @@
true, /* secure */
true, /* supports protected content */
accumClearRegion,
+ kPortraitViewport,
+ kOutputDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
EXPECT_CALL(leftLayer.mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true));
EXPECT_CALL(leftLayer.mOutputLayer, needsFiltering()).WillRepeatedly(Return(false));
- EXPECT_CALL(leftLayer.mLayerFE, prepareClientComposition(Eq(ByRef(leftLayerSettings))))
- .WillOnce(Return(leftLayer.mLayerSettings));
- EXPECT_CALL(leftLayer.mLayerFE,
- prepareShadowClientComposition(leftLayer.mLayerSettings, kPortraitViewport,
- kOutputDataspace))
- .WillOnce(Return(std::nullopt));
+ EXPECT_CALL(leftLayer.mLayerFE, prepareClientCompositionList(Eq(ByRef(leftLayerSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>({leftLayer.mLayerSettings})));
compositionengine::LayerFE::ClientCompositionTargetSettings rightLayerSettings{
Region(Rect(1000, 0, 2000, 1000)),
@@ -3865,16 +3942,16 @@
true, /* secure */
true, /* supports protected content */
accumClearRegion,
+ kPortraitViewport,
+ kOutputDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
EXPECT_CALL(rightLayer.mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true));
EXPECT_CALL(rightLayer.mOutputLayer, needsFiltering()).WillRepeatedly(Return(false));
- EXPECT_CALL(rightLayer.mLayerFE, prepareClientComposition(Eq(ByRef(rightLayerSettings))))
- .WillOnce(Return(rightLayer.mLayerSettings));
- EXPECT_CALL(rightLayer.mLayerFE,
- prepareShadowClientComposition(rightLayer.mLayerSettings, kPortraitViewport,
- kOutputDataspace))
- .WillOnce(Return(std::nullopt));
+ EXPECT_CALL(rightLayer.mLayerFE, prepareClientCompositionList(Eq(ByRef(rightLayerSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>({rightLayer.mLayerSettings})));
constexpr bool supportsProtectedContent = true;
auto requests = mOutput.generateClientCompositionRequests(supportsProtectedContent,
@@ -3891,6 +3968,20 @@
const Region kShadowRegion = Region(kContentWithShadow).subtract(kContent);
const Region kPartialShadowRegion = Region(kContentWithShadow).subtract(Rect(40, 40, 60, 80));
+ Region accumClearRegion(Rect(10, 11, 12, 13));
+ compositionengine::LayerFE::ClientCompositionTargetSettings layer2Settings{
+ Region(Rect(60, 40, 70, 80)).merge(Rect(40, 80, 70, 90)), /* visible region */
+ false, /* identity transform */
+ false, /* needs filtering */
+ false, /* secure */
+ false, /* supports protected content */
+ accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ false /* realContentIsVisible */,
+ false /* clearContent */,
+ };
+
LayerFE::LayerSettings mShadowSettings;
mShadowSettings.source.solidColor = {0.1f, 0.1f, 0.1f};
@@ -3899,14 +3990,9 @@
EXPECT_CALL(mLayers[0].mOutputLayer, requiresClientComposition()).WillOnce(Return(false));
EXPECT_CALL(mLayers[1].mOutputLayer, requiresClientComposition()).WillOnce(Return(false));
- EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[2].mLayerSettings));
- EXPECT_CALL(mLayers[2].mLayerFE,
- prepareShadowClientComposition(mLayers[2].mLayerSettings, kDisplayViewport,
- kDisplayDataspace))
- .WillOnce(Return(mShadowSettings));
+ EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2Settings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mShadowSettings})));
- Region accumClearRegion(Rect(10, 11, 12, 13));
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
accumClearRegion, kDisplayDataspace);
ASSERT_EQ(1u, requests.size());
@@ -3928,16 +4014,26 @@
mLayers[2].mOutputLayerState.visibleRegion = kPartialContentWithPartialShadowRegion;
mLayers[2].mOutputLayerState.shadowRegion = kShadowRegion;
+ Region accumClearRegion(Rect(10, 11, 12, 13));
+ compositionengine::LayerFE::ClientCompositionTargetSettings layer2Settings{
+ Region(Rect(50, 40, 70, 80)).merge(Rect(40, 80, 70, 90)), /* visible region */
+ false, /* identity transform */
+ false, /* needs filtering */
+ false, /* secure */
+ false, /* supports protected content */
+ accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
+ };
+
EXPECT_CALL(mLayers[0].mOutputLayer, requiresClientComposition()).WillOnce(Return(false));
EXPECT_CALL(mLayers[1].mOutputLayer, requiresClientComposition()).WillOnce(Return(false));
- EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[2].mLayerSettings));
- EXPECT_CALL(mLayers[2].mLayerFE,
- prepareShadowClientComposition(mLayers[2].mLayerSettings, kDisplayViewport,
- kDisplayDataspace))
- .WillOnce(Return(mShadowSettings));
+ EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2Settings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>(
+ {mShadowSettings, mLayers[2].mLayerSettings})));
- Region accumClearRegion(Rect(10, 11, 12, 13));
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
accumClearRegion, kDisplayDataspace);
ASSERT_EQ(2u, requests.size());
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 6ff39b4..cd6bbd1 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -49,16 +49,16 @@
DisplayDeviceCreationArgs::DisplayDeviceCreationArgs(const sp<SurfaceFlinger>& flinger,
const wp<IBinder>& displayToken,
- const std::optional<DisplayId>& displayId)
+ std::optional<DisplayId> displayId)
: flinger(flinger), displayToken(displayToken), displayId(displayId) {}
DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs&& args)
: mFlinger(args.flinger),
mDisplayToken(args.displayToken),
mSequenceId(args.sequenceId),
- mIsVirtual(args.isVirtual),
+ mConnectionType(args.connectionType),
mCompositionDisplay{mFlinger->getCompositionEngine().createDisplay(
- compositionengine::DisplayCreationArgs{args.isVirtual, args.displayId,
+ compositionengine::DisplayCreationArgs{args.isVirtual(), args.displayId,
args.powerAdvisor})},
mPhysicalOrientation(args.physicalOrientation),
mIsPrimary(args.isPrimary) {
@@ -248,10 +248,18 @@
}
std::string DisplayDevice::getDebugName() const {
- const auto id = getId() ? to_string(*getId()) + ", " : std::string();
- return base::StringPrintf("DisplayDevice{%s%s%s\"%s\"}", id.c_str(),
- isPrimary() ? "primary, " : "", isVirtual() ? "virtual, " : "",
- mDisplayName.c_str());
+ std::string displayId;
+ if (const auto id = getId()) {
+ displayId = to_string(*id) + ", ";
+ }
+
+ const char* type = "virtual";
+ if (mConnectionType) {
+ type = *mConnectionType == DisplayConnectionType::Internal ? "internal" : "external";
+ }
+
+ return base::StringPrintf("DisplayDevice{%s%s%s, \"%s\"}", displayId.c_str(), type,
+ isPrimary() ? ", primary" : "", mDisplayName.c_str());
}
void DisplayDevice::dump(std::string& result) const {
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index f45feae..d970b82 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -28,6 +28,7 @@
#include <math/mat4.h>
#include <renderengine/RenderEngine.h>
#include <system/window.h>
+#include <ui/DisplayInfo.h>
#include <ui/DisplayState.h>
#include <ui/GraphicTypes.h>
#include <ui/HdrCapabilities.h>
@@ -52,7 +53,6 @@
struct CompositionInfo;
struct DisplayDeviceCreationArgs;
-struct DisplayInfo;
namespace compositionengine {
class Display;
@@ -71,7 +71,9 @@
return mCompositionDisplay;
}
- bool isVirtual() const { return mIsVirtual; }
+ std::optional<DisplayConnectionType> getConnectionType() const { return mConnectionType; }
+
+ bool isVirtual() const { return !mConnectionType; }
bool isPrimary() const { return mIsPrimary; }
// isSecure indicates whether this display can be trusted to display
@@ -159,7 +161,7 @@
const sp<SurfaceFlinger> mFlinger;
const wp<IBinder> mDisplayToken;
const int32_t mSequenceId;
- const bool mIsVirtual;
+ const std::optional<DisplayConnectionType> mConnectionType;
const std::shared_ptr<compositionengine::Display> mCompositionDisplay;
@@ -178,10 +180,19 @@
};
struct DisplayDeviceState {
- bool isVirtual() const { return !displayId.has_value(); }
+ struct Physical {
+ DisplayId id;
+ DisplayConnectionType type;
+
+ bool operator==(const Physical& other) const {
+ return id == other.id && type == other.type;
+ }
+ };
+
+ bool isVirtual() const { return !physical; }
int32_t sequenceId = sNextSequenceId++;
- std::optional<DisplayId> displayId;
+ std::optional<Physical> physical;
sp<IGraphicBufferProducer> surface;
ui::LayerStack layerStack = ui::NO_LAYER_STACK;
Rect viewport;
@@ -199,15 +210,17 @@
struct DisplayDeviceCreationArgs {
// We use a constructor to ensure some of the values are set, without
// assuming a default value.
- DisplayDeviceCreationArgs(const sp<SurfaceFlinger>& flinger, const wp<IBinder>& displayToken,
- const std::optional<DisplayId>& displayId);
+ DisplayDeviceCreationArgs(const sp<SurfaceFlinger>&, const wp<IBinder>& displayToken,
+ std::optional<DisplayId>);
+
+ bool isVirtual() const { return !connectionType; }
const sp<SurfaceFlinger> flinger;
const wp<IBinder> displayToken;
const std::optional<DisplayId> displayId;
int32_t sequenceId{0};
- bool isVirtual{false};
+ std::optional<DisplayConnectionType> connectionType;
bool isSecure{false};
sp<ANativeWindow> nativeWindow;
sp<compositionengine::DisplaySurface> displaySurface;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 41e7879..fc5d441 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -95,13 +95,13 @@
}
namespace impl {
+
Display::Display(android::Hwc2::Composer& composer,
const std::unordered_set<Capability>& capabilities, hwc2_display_t id,
DisplayType type)
: mComposer(composer),
mCapabilities(capabilities),
mId(id),
- mIsConnected(false),
mType(type) {
ALOGV("Created display %" PRIu64, id);
}
@@ -109,20 +109,27 @@
Display::~Display() {
mLayers.clear();
- if (mType == DisplayType::Virtual) {
- ALOGV("Destroying virtual display");
- auto intError = mComposer.destroyVirtualDisplay(mId);
- auto error = static_cast<Error>(intError);
- ALOGE_IF(error != Error::None, "destroyVirtualDisplay(%" PRIu64
- ") failed: %s (%d)", mId, to_string(error).c_str(), intError);
- } else if (mType == DisplayType::Physical) {
- auto error = setVsyncEnabled(HWC2::Vsync::Disable);
- if (error != Error::None) {
- ALOGE("~Display: Failed to disable vsync for display %" PRIu64
- ": %s (%d)", mId, to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
+ Error error = Error::None;
+ const char* msg;
+ switch (mType) {
+ case DisplayType::Physical:
+ error = setVsyncEnabled(HWC2::Vsync::Disable);
+ msg = "disable VSYNC for";
+ break;
+
+ case DisplayType::Virtual:
+ error = static_cast<Error>(mComposer.destroyVirtualDisplay(mId));
+ msg = "destroy virtual";
+ break;
+
+ case DisplayType::Invalid: // Used in unit tests.
+ break;
}
+
+ ALOGE_IF(error != Error::None, "%s: Failed to %s display %" PRIu64 ": %s (%d)", __FUNCTION__,
+ msg, mId, to_string(error).c_str(), static_cast<int32_t>(error));
+
+ ALOGV("Destroyed display %" PRIu64, mId);
}
// Required by HWC2 display
@@ -372,9 +379,19 @@
return Error::None;
}
-Error Display::getType(DisplayType* outType) const
-{
- *outType = mType;
+Error Display::getConnectionType(android::DisplayConnectionType* outType) const {
+ if (mType != DisplayType::Physical) return Error::BadDisplay;
+
+ using ConnectionType = Hwc2::IComposerClient::DisplayConnectionType;
+ ConnectionType connectionType;
+ const auto error = static_cast<Error>(mComposer.getDisplayConnectionType(mId, &connectionType));
+ if (error != Error::None) {
+ return error;
+ }
+
+ *outType = connectionType == ConnectionType::INTERNAL
+ ? android::DisplayConnectionType::Internal
+ : android::DisplayConnectionType::External;
return Error::None;
}
@@ -734,12 +751,11 @@
Layer::Layer(android::Hwc2::Composer& composer, const std::unordered_set<Capability>& capabilities,
hwc2_display_t displayId, hwc2_layer_t layerId)
- : mComposer(composer),
- mCapabilities(capabilities),
- mDisplayId(displayId),
- mId(layerId),
- mColorMatrix(android::mat4())
-{
+ : mComposer(composer),
+ mCapabilities(capabilities),
+ mDisplayId(displayId),
+ mId(layerId),
+ mColorMatrix(android::mat4()) {
ALOGV("Created layer %" PRIu64 " on display %" PRIu64, layerId, displayId);
}
@@ -979,6 +995,13 @@
return error;
}
+// Composer HAL 2.4
+Error Layer::setLayerGenericMetadata(const std::string& name, bool mandatory,
+ const std::vector<uint8_t>& value) {
+ auto intError = mComposer.setLayerGenericMetadata(mDisplayId, mId, name, mandatory, value);
+ return static_cast<Error>(intError);
+}
+
} // namespace impl
} // namespace HWC2
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index e7cf5ff..6549525 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -25,6 +25,7 @@
#include <gui/HdrMetadata.h>
#include <math/mat4.h>
+#include <ui/DisplayInfo.h>
#include <ui/GraphicTypes.h>
#include <ui/HdrCapabilities.h>
#include <ui/Region.h>
@@ -191,7 +192,8 @@
[[clang::warn_unused_result]] virtual Error getRequests(
DisplayRequest* outDisplayRequests,
std::unordered_map<Layer*, LayerRequest>* outLayerRequests) = 0;
- [[clang::warn_unused_result]] virtual Error getType(DisplayType* outType) const = 0;
+ [[clang::warn_unused_result]] virtual Error getConnectionType(
+ android::DisplayConnectionType*) const = 0;
[[clang::warn_unused_result]] virtual Error supportsDoze(bool* outSupport) const = 0;
[[clang::warn_unused_result]] virtual Error getHdrCapabilities(
android::HdrCapabilities* outCapabilities) const = 0;
@@ -268,7 +270,7 @@
Error getName(std::string* outName) const override;
Error getRequests(DisplayRequest* outDisplayRequests,
std::unordered_map<Layer*, LayerRequest>* outLayerRequests) override;
- Error getType(DisplayType* outType) const override;
+ Error getConnectionType(android::DisplayConnectionType*) const override;
Error supportsDoze(bool* outSupport) const override;
Error getHdrCapabilities(android::HdrCapabilities* outCapabilities) const override;
Error getDisplayedContentSamplingAttributes(android::ui::PixelFormat* outFormat,
@@ -332,16 +334,17 @@
android::Hwc2::Composer& mComposer;
const std::unordered_set<Capability>& mCapabilities;
- hwc2_display_t mId;
- bool mIsConnected;
+ const hwc2_display_t mId;
DisplayType mType;
- std::unordered_map<hwc2_layer_t, std::unique_ptr<Layer>> mLayers;
+ bool mIsConnected = false;
+ std::unordered_map<hwc2_layer_t, std::unique_ptr<Layer>> mLayers;
std::unordered_map<hwc2_config_t, std::shared_ptr<const Config>> mConfigs;
std::once_flag mDisplayCapabilityQueryFlag;
std::unordered_set<DisplayCapability> mDisplayCapabilities;
};
+
} // namespace impl
class Layer {
@@ -374,6 +377,10 @@
// Composer HAL 2.3
[[clang::warn_unused_result]] virtual Error setColorTransform(const android::mat4& matrix) = 0;
+
+ // Composer HAL 2.4
+ [[clang::warn_unused_result]] virtual Error setLayerGenericMetadata(
+ const std::string& name, bool mandatory, const std::vector<uint8_t>& value) = 0;
};
namespace impl {
@@ -382,8 +389,7 @@
class Layer : public HWC2::Layer {
public:
- Layer(android::Hwc2::Composer& composer,
- const std::unordered_set<Capability>& capabilities,
+ Layer(android::Hwc2::Composer& composer, const std::unordered_set<Capability>& capabilities,
hwc2_display_t displayId, hwc2_layer_t layerId);
~Layer() override;
@@ -412,6 +418,10 @@
// Composer HAL 2.3
Error setColorTransform(const android::mat4& matrix) override;
+ // Composer HAL 2.4
+ Error setLayerGenericMetadata(const std::string& name, bool mandatory,
+ const std::vector<uint8_t>& value) override;
+
private:
// These are references to data owned by HWC2::Device, which will outlive
// this HWC2::Layer, so these references are guaranteed to be valid for
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index f8d45c0..784fa74 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -148,20 +148,20 @@
namespace impl {
HWComposer::HWComposer(std::unique_ptr<Hwc2::Composer> composer) : mComposer(std::move(composer)) {
- loadCapabilities();
}
HWComposer::HWComposer(const std::string& composerServiceName)
: mComposer(std::make_unique<Hwc2::impl::Composer>(composerServiceName)) {
- loadCapabilities();
}
HWComposer::~HWComposer() {
mDisplayData.clear();
}
-void HWComposer::registerCallback(HWC2::ComposerCallback* callback,
- int32_t sequenceId) {
+void HWComposer::setConfiguration(HWC2::ComposerCallback* callback, int32_t sequenceId) {
+ loadCapabilities();
+ loadLayerMetadataSupport();
+
if (mRegisteredCallback) {
ALOGW("Callback already registered. Ignored extra registration attempt.");
return;
@@ -405,18 +405,32 @@
// Composer 2.4
+DisplayConnectionType HWComposer::getDisplayConnectionType(DisplayId displayId) const {
+ RETURN_IF_INVALID_DISPLAY(displayId, DisplayConnectionType::Internal);
+ const auto& hwcDisplay = mDisplayData.at(displayId).hwcDisplay;
+
+ DisplayConnectionType type;
+ const auto error = hwcDisplay->getConnectionType(&type);
+
+ const auto FALLBACK_TYPE = hwcDisplay->getId() == mInternalHwcDisplayId
+ ? DisplayConnectionType::Internal
+ : DisplayConnectionType::External;
+
+ RETURN_IF_HWC_ERROR(error, displayId, FALLBACK_TYPE);
+ return type;
+}
+
bool HWComposer::isVsyncPeriodSwitchSupported(DisplayId displayId) const {
+ RETURN_IF_INVALID_DISPLAY(displayId, false);
return mDisplayData.at(displayId).hwcDisplay->isVsyncPeriodSwitchSupported();
}
nsecs_t HWComposer::getDisplayVsyncPeriod(DisplayId displayId) const {
+ RETURN_IF_INVALID_DISPLAY(displayId, 0);
+
nsecs_t vsyncPeriodNanos;
auto error = mDisplayData.at(displayId).hwcDisplay->getDisplayVsyncPeriod(&vsyncPeriodNanos);
- if (error != HWC2::Error::None) {
- LOG_DISPLAY_ERROR(displayId, "Failed to get Vsync Period");
- return 0;
- }
-
+ RETURN_IF_HWC_ERROR(error, displayId, 0);
return vsyncPeriodNanos;
}
@@ -871,6 +885,10 @@
return NO_ERROR;
}
+const std::unordered_map<std::string, bool>& HWComposer::getSupportedLayerGenericMetadata() const {
+ return mSupportedLayerGenericMetadata;
+}
+
void HWComposer::dump(std::string& result) const {
result.append(mComposer->dumpDebugInfo());
}
@@ -946,6 +964,22 @@
}
}
+void HWComposer::loadLayerMetadataSupport() {
+ mSupportedLayerGenericMetadata.clear();
+
+ std::vector<Hwc2::IComposerClient::LayerGenericMetadataKey> supportedMetadataKeyInfo;
+ const auto error = mComposer->getLayerGenericMetadataKeys(&supportedMetadataKeyInfo);
+ if (error != hardware::graphics::composer::V2_4::Error::NONE) {
+ ALOGE("%s: %s failed: %s (%d)", __FUNCTION__, "getLayerGenericMetadataKeys",
+ toString(error).c_str(), static_cast<int32_t>(error));
+ return;
+ }
+
+ for (const auto& [name, mandatory] : supportedMetadataKeyInfo) {
+ mSupportedLayerGenericMetadata.emplace(name, mandatory);
+ }
+}
+
uint32_t HWComposer::getMaxVirtualDisplayCount() const {
return mComposer->getMaxVirtualDisplayCount();
}
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index effe43b..41db501 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -55,11 +55,16 @@
class Output;
} // namespace compositionengine
+struct KnownHWCGenericLayerMetadata {
+ const char* name;
+ const uint32_t id;
+};
+
class HWComposer {
public:
virtual ~HWComposer();
- virtual void registerCallback(HWC2::ComposerCallback* callback, int32_t sequenceId) = 0;
+ virtual void setConfiguration(HWC2::ComposerCallback* callback, int32_t sequenceId) = 0;
virtual bool getDisplayIdentificationData(hwc2_display_t hwcDisplayId, uint8_t* outPort,
DisplayIdentificationData* outData) const = 0;
@@ -184,6 +189,7 @@
virtual bool isUsingVrComposer() const = 0;
// Composer 2.4
+ virtual DisplayConnectionType getDisplayConnectionType(DisplayId) const = 0;
virtual bool isVsyncPeriodSwitchSupported(DisplayId displayId) const = 0;
virtual nsecs_t getDisplayVsyncPeriod(DisplayId displayId) const = 0;
virtual status_t setActiveConfigWithConstraints(
@@ -194,6 +200,8 @@
virtual status_t getSupportedContentTypes(
DisplayId displayId, std::vector<HWC2::ContentType>* outSupportedContentTypes) = 0;
virtual status_t setContentType(DisplayId displayId, HWC2::ContentType contentType) = 0;
+ virtual const std::unordered_map<std::string, bool>& getSupportedLayerGenericMetadata()
+ const = 0;
// for debugging ----------------------------------------------------------
virtual void dump(std::string& out) const = 0;
@@ -217,7 +225,7 @@
~HWComposer() override;
- void registerCallback(HWC2::ComposerCallback* callback, int32_t sequenceId) override;
+ void setConfiguration(HWC2::ComposerCallback* callback, int32_t sequenceId) override;
bool getDisplayIdentificationData(hwc2_display_t hwcDisplayId, uint8_t* outPort,
DisplayIdentificationData* outData) const override;
@@ -319,6 +327,7 @@
bool isUsingVrComposer() const override;
// Composer 2.4
+ DisplayConnectionType getDisplayConnectionType(DisplayId) const override;
bool isVsyncPeriodSwitchSupported(DisplayId displayId) const override;
nsecs_t getDisplayVsyncPeriod(DisplayId displayId) const override;
status_t setActiveConfigWithConstraints(DisplayId displayId, size_t configId,
@@ -329,6 +338,8 @@
std::vector<HWC2::ContentType>*) override;
status_t setContentType(DisplayId displayId, HWC2::ContentType) override;
+ const std::unordered_map<std::string, bool>& getSupportedLayerGenericMetadata() const override;
+
// for debugging ----------------------------------------------------------
void dump(std::string& out) const override;
@@ -351,6 +362,7 @@
std::optional<DisplayIdentificationInfo> onHotplugConnect(hwc2_display_t hwcDisplayId);
void loadCapabilities();
+ void loadLayerMetadataSupport();
uint32_t getMaxVirtualDisplayCount() const;
struct DisplayData {
@@ -379,6 +391,7 @@
std::unique_ptr<android::Hwc2::Composer> mComposer;
std::unordered_set<HWC2::Capability> mCapabilities;
+ std::unordered_map<std::string, bool> mSupportedLayerGenericMetadata;
bool mRegisteredCallback = false;
std::unordered_map<hwc2_display_t, DisplayId> mPhysicalDisplayIdMap;
diff --git a/services/surfaceflinger/EffectLayer.cpp b/services/surfaceflinger/EffectLayer.cpp
new file mode 100644
index 0000000..9d45e33
--- /dev/null
+++ b/services/surfaceflinger/EffectLayer.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+// #define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "EffectLayer"
+
+#include "EffectLayer.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/LayerFECompositionState.h>
+#include <renderengine/RenderEngine.h>
+#include <ui/GraphicBuffer.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include "DisplayDevice.h"
+#include "SurfaceFlinger.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+EffectLayer::EffectLayer(const LayerCreationArgs& args)
+ : Layer(args),
+ mCompositionState{mFlinger->getCompositionEngine().createLayerFECompositionState()} {}
+
+EffectLayer::~EffectLayer() = default;
+
+std::vector<compositionengine::LayerFE::LayerSettings> EffectLayer::prepareClientCompositionList(
+ compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
+ std::vector<compositionengine::LayerFE::LayerSettings> results;
+ std::optional<compositionengine::LayerFE::LayerSettings> layerSettings =
+ prepareClientComposition(targetSettings);
+ // Nothing to render.
+ if (!layerSettings) {
+ return {};
+ }
+
+ std::optional<compositionengine::LayerFE::LayerSettings> shadowSettings =
+ prepareShadowClientComposition(*layerSettings, targetSettings.viewport,
+ targetSettings.dataspace);
+ if (shadowSettings) {
+ results.push_back(*shadowSettings);
+ }
+
+ // If fill bounds are occluded or the fill color is invalid skip the fill settings.
+ if (targetSettings.realContentIsVisible && fillsColor()) {
+ // Set color for color fill settings.
+ layerSettings->source.solidColor = getColor().rgb;
+ results.push_back(*layerSettings);
+ }
+
+ return results;
+}
+
+bool EffectLayer::isVisible() const {
+ return !isHiddenByPolicy() && getAlpha() > 0.0_hf && hasSomethingToDraw();
+}
+
+bool EffectLayer::setColor(const half3& color) {
+ if (mCurrentState.color.r == color.r && mCurrentState.color.g == color.g &&
+ mCurrentState.color.b == color.b) {
+ return false;
+ }
+
+ mCurrentState.sequence++;
+ mCurrentState.color.r = color.r;
+ mCurrentState.color.g = color.g;
+ mCurrentState.color.b = color.b;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
+bool EffectLayer::setDataspace(ui::Dataspace dataspace) {
+ if (mCurrentState.dataspace == dataspace) {
+ return false;
+ }
+
+ mCurrentState.sequence++;
+ mCurrentState.dataspace = dataspace;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
+void EffectLayer::preparePerFrameCompositionState() {
+ Layer::preparePerFrameCompositionState();
+
+ auto* compositionState = editCompositionState();
+ compositionState->color = getColor();
+ compositionState->compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
+}
+
+sp<compositionengine::LayerFE> EffectLayer::getCompositionEngineLayerFE() const {
+ return asLayerFE();
+}
+
+compositionengine::LayerFECompositionState* EffectLayer::editCompositionState() {
+ return mCompositionState.get();
+}
+
+const compositionengine::LayerFECompositionState* EffectLayer::getCompositionState() const {
+ return mCompositionState.get();
+}
+
+bool EffectLayer::isOpaque(const Layer::State& s) const {
+ // Consider the layer to be opaque if its opaque flag is set or its effective
+ // alpha (considering the alpha of its parents as well) is 1.0;
+ return (s.flags & layer_state_t::eLayerOpaque) != 0 || getAlpha() == 1.0_hf;
+}
+
+ui::Dataspace EffectLayer::getDataSpace() const {
+ return mDrawingState.dataspace;
+}
+
+sp<Layer> EffectLayer::createClone() {
+ sp<EffectLayer> layer = mFlinger->getFactory().createEffectLayer(
+ LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0,
+ LayerMetadata()));
+ layer->setInitialValuesForClone(this);
+ return layer;
+}
+
+bool EffectLayer::fillsColor() const {
+ return mDrawingState.color.r >= 0.0_hf && mDrawingState.color.g >= 0.0_hf &&
+ mDrawingState.color.b >= 0.0_hf;
+}
+
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/EffectLayer.h
similarity index 68%
rename from services/surfaceflinger/ColorLayer.h
rename to services/surfaceflinger/EffectLayer.h
index 4deb162..33758b6 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/EffectLayer.h
@@ -23,15 +23,19 @@
namespace android {
-class ColorLayer : public Layer {
+// A layer that can render a combination of the following effects.
+// * fill the bounds of the layer with a color
+// * render a shadow cast by the bounds of the layer
+// If no effects are enabled, the layer is considered to be invisible.
+class EffectLayer : public Layer {
public:
- explicit ColorLayer(const LayerCreationArgs&);
- ~ColorLayer() override;
+ explicit EffectLayer(const LayerCreationArgs&);
+ ~EffectLayer() override;
sp<compositionengine::LayerFE> getCompositionEngineLayerFE() const override;
compositionengine::LayerFECompositionState* editCompositionState() override;
- const char* getType() const override { return "ColorLayer"; }
+ const char* getType() const override { return "EffectLayer"; }
bool isVisible() const override;
bool setColor(const half3& color) override;
@@ -48,12 +52,17 @@
*/
const compositionengine::LayerFECompositionState* getCompositionState() const override;
void preparePerFrameCompositionState() override;
- std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
- compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
+ std::vector<compositionengine::LayerFE::LayerSettings> prepareClientCompositionList(
+ compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) override;
std::unique_ptr<compositionengine::LayerFECompositionState> mCompositionState;
sp<Layer> createClone() override;
+
+private:
+ // Returns true if there is a valid color to fill.
+ bool fillsColor() const;
+ bool hasSomethingToDraw() const { return fillsColor() || drawShadows(); }
};
} // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 6ff23c5..da26a37 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -56,10 +56,10 @@
#include <sstream>
#include "BufferLayer.h"
-#include "ColorLayer.h"
#include "Colorizer.h"
#include "DisplayDevice.h"
#include "DisplayHardware/HWComposer.h"
+#include "EffectLayer.h"
#include "FrameTracer/FrameTracer.h"
#include "LayerProtoHelper.h"
#include "LayerRejecter.h"
@@ -164,7 +164,7 @@
/*
* onLayerDisplayed is only meaningful for BufferLayer, but, is called through
* Layer. So, the implementation is done in BufferLayer. When called on a
- * ColorLayer object, it's essentially a NOP.
+ * EffectLayer object, it's essentially a NOP.
*/
void Layer::onLayerDisplayed(const sp<Fence>& /*releaseFence*/) {}
@@ -475,6 +475,26 @@
compositionState->type = type;
compositionState->appId = appId;
+
+ compositionState->metadata.clear();
+ const auto& supportedMetadata = mFlinger->getHwComposer().getSupportedLayerGenericMetadata();
+ for (const auto& [key, mandatory] : supportedMetadata) {
+ const auto& genericLayerMetadataCompatibilityMap =
+ mFlinger->getGenericLayerMetadataKeyMap();
+ auto compatIter = genericLayerMetadataCompatibilityMap.find(key);
+ if (compatIter == std::end(genericLayerMetadataCompatibilityMap)) {
+ continue;
+ }
+ const uint32_t id = compatIter->second;
+
+ auto it = drawingState.metadata.mMap.find(id);
+ if (it == std::end(drawingState.metadata.mMap)) {
+ continue;
+ }
+
+ compositionState->metadata
+ .emplace(key, compositionengine::GenericLayerMetadataEntry{mandatory, it->second});
+ }
}
void Layer::preparePerFrameCompositionState() {
@@ -491,13 +511,12 @@
compositionState->hasProtectedContent = isProtected();
const bool usesRoundedCorners = getRoundedCornerState().radius != 0.f;
- const bool drawsShadows = mEffectiveShadowRadius != 0.f;
compositionState->isOpaque =
isOpaque(drawingState) && !usesRoundedCorners && getAlpha() == 1.0_hf;
// Force client composition for special cases known only to the front-end.
- if (isHdrY410() || usesRoundedCorners || drawsShadows) {
+ if (isHdrY410() || usesRoundedCorners || drawShadows()) {
compositionState->forceClientComposition = true;
}
}
@@ -652,6 +671,49 @@
return shadowLayer;
}
+void Layer::prepareClearClientComposition(LayerFE::LayerSettings& layerSettings,
+ bool blackout) const {
+ layerSettings.source.buffer.buffer = nullptr;
+ layerSettings.source.solidColor = half3(0.0, 0.0, 0.0);
+ layerSettings.disableBlending = true;
+ layerSettings.frameNumber = 0;
+
+ // If layer is blacked out, force alpha to 1 so that we draw a black color layer.
+ layerSettings.alpha = blackout ? 1.0f : 0.0f;
+}
+
+std::vector<compositionengine::LayerFE::LayerSettings> Layer::prepareClientCompositionList(
+ compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
+ std::optional<compositionengine::LayerFE::LayerSettings> layerSettings =
+ prepareClientComposition(targetSettings);
+ // Nothing to render.
+ if (!layerSettings) {
+ return {};
+ }
+
+ // HWC requests to clear this layer.
+ if (targetSettings.clearContent) {
+ prepareClearClientComposition(*layerSettings, false /* blackout */);
+ return {*layerSettings};
+ }
+
+ std::optional<compositionengine::LayerFE::LayerSettings> shadowSettings =
+ prepareShadowClientComposition(*layerSettings, targetSettings.viewport,
+ targetSettings.dataspace);
+ // There are no shadows to render.
+ if (!shadowSettings) {
+ return {*layerSettings};
+ }
+
+ // If the layer casts a shadow but the content casting the shadow is occluded, skip
+ // composing the non-shadow content and only draw the shadows.
+ if (targetSettings.realContentIsVisible) {
+ return {*shadowSettings, *layerSettings};
+ }
+
+ return {*shadowSettings};
+}
+
Hwc2::IComposerClient::Composition Layer::getCompositionType(
const sp<const DisplayDevice>& display) const {
const auto outputLayer = findOutputLayerForDisplay(display);
@@ -1091,9 +1153,9 @@
if (!mCurrentState.bgColorLayer && alpha != 0) {
// create background color layer if one does not yet exist
- uint32_t flags = ISurfaceComposerClient::eFXSurfaceColor;
+ uint32_t flags = ISurfaceComposerClient::eFXSurfaceEffect;
std::string name = mName + "BackgroundColorLayer";
- mCurrentState.bgColorLayer = mFlinger->getFactory().createColorLayer(
+ mCurrentState.bgColorLayer = mFlinger->getFactory().createEffectLayer(
LayerCreationArgs(mFlinger.get(), nullptr, std::move(name), 0, 0, flags,
LayerMetadata()));
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index c110462..37ae340 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -212,7 +212,7 @@
InputWindowInfo inputInfo;
wp<Layer> touchableRegionCrop;
- // dataspace is only used by BufferStateLayer and ColorLayer
+ // dataspace is only used by BufferStateLayer and EffectLayer
ui::Dataspace dataspace;
// The fields below this point are only used by BufferStateLayer
@@ -552,6 +552,14 @@
void updateClonedRelatives(const std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
void addChildToDrawing(const sp<Layer>& layer);
void updateClonedInputInfo(const std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
+ virtual std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
+ compositionengine::LayerFE::ClientCompositionTargetSettings&);
+ virtual std::optional<compositionengine::LayerFE::LayerSettings> prepareShadowClientComposition(
+ const LayerFE::LayerSettings& layerSettings, const Rect& displayViewport,
+ ui::Dataspace outputDataspace);
+ // Modifies the passed in layer settings to clear the contents. If the blackout flag is set,
+ // the settings clears the content with a solid black fill.
+ void prepareClearClientComposition(LayerFE::LayerSettings& layerSettings, bool blackout) const;
public:
/*
@@ -560,11 +568,8 @@
const compositionengine::LayerFECompositionState* getCompositionState() const override;
bool onPreComposition(nsecs_t) override;
void prepareCompositionState(compositionengine::LayerFE::StateSubset subset) override;
- std::optional<LayerSettings> prepareClientComposition(
+ std::vector<compositionengine::LayerFE::LayerSettings> prepareClientCompositionList(
compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
- std::optional<LayerSettings> prepareShadowClientComposition(
- const LayerFE::LayerSettings& layerSettings, const Rect& displayViewport,
- ui::Dataspace outputDataspace) override;
void onLayerDisplayed(const sp<Fence>& releaseFence) override;
const char* getDebugName() const override;
@@ -704,6 +709,7 @@
half getAlpha() const;
half4 getColor() const;
int32_t getBackgroundBlurRadius() const;
+ bool drawShadows() const { return mEffectiveShadowRadius > 0.f; };
// Returns how rounded corners should be drawn for this layer.
// This will traverse the hierarchy until it reaches its root, finding topmost rounded
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 14e3ec6..acab5a6 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -335,6 +335,11 @@
mCondition.notify_all();
}
+size_t EventThread::getEventThreadConnectionCount() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mDisplayEventConnections.size();
+}
+
void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
DisplayEventConsumers consumers;
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 641b2a5..466234d 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -16,7 +16,12 @@
#pragma once
+#include <android-base/thread_annotations.h>
+#include <gui/DisplayEventReceiver.h>
+#include <gui/IDisplayEventConnection.h>
+#include <private/gui/BitTube.h>
#include <sys/types.h>
+#include <utils/Errors.h>
#include <condition_variable>
#include <cstdint>
@@ -26,13 +31,6 @@
#include <thread>
#include <vector>
-#include <android-base/thread_annotations.h>
-
-#include <gui/DisplayEventReceiver.h>
-#include <gui/IDisplayEventConnection.h>
-#include <private/gui/BitTube.h>
-
-#include <utils/Errors.h>
#include "HwcStrongTypes.h"
// ---------------------------------------------------------------------------
@@ -134,6 +132,9 @@
// Usage of this method assumes that only the primary internal display
// supports multiple display configurations.
virtual void requestLatestConfig() = 0;
+
+ // Retrieves the number of event connections tracked by this EventThread.
+ virtual size_t getEventThreadConnectionCount() = 0;
};
namespace impl {
@@ -168,6 +169,8 @@
void setPhaseOffset(nsecs_t phaseOffset) override;
+ size_t getEventThreadConnectionCount() override;
+
private:
friend EventThreadTest;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 8202515..d1de737 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -194,9 +194,22 @@
}
}
- float max = 0;
+ // Now that we scored all the refresh rates we need to pick the one that got the highest score.
+ // In case of a tie we will pick the higher refresh rate if any of the layers wanted Max,
+ // or the lower otherwise.
+ const RefreshRate* bestRefreshRate = maxVoteLayers > 0
+ ? getBestRefreshRate(scores.rbegin(), scores.rend())
+ : getBestRefreshRate(scores.begin(), scores.end());
+
+ return bestRefreshRate == nullptr ? *mCurrentRefreshRate : *bestRefreshRate;
+}
+
+template <typename Iter>
+const RefreshRate* RefreshRateConfigs::getBestRefreshRate(Iter begin, Iter end) const {
const RefreshRate* bestRefreshRate = nullptr;
- for (const auto [refreshRate, score] : scores) {
+ float max = 0;
+ for (auto i = begin; i != end; ++i) {
+ const auto [refreshRate, score] = *i;
ALOGV("%s scores %.2f", refreshRate->name.c_str(), score);
ATRACE_INT(refreshRate->name.c_str(), round<int>(score * 100));
@@ -207,7 +220,7 @@
}
}
- return bestRefreshRate == nullptr ? *mCurrentRefreshRate : *bestRefreshRate;
+ return bestRefreshRate;
}
const AllRefreshRatesMapType& RefreshRateConfigs::getAllRefreshRates() const {
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index e5bb557..1132a8c 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -182,6 +182,12 @@
const std::function<bool(const RefreshRate&)>& shouldAddRefreshRate,
std::vector<const RefreshRate*>* outRefreshRates);
+ // Returns the refresh rate with the highest score in the collection specified from begin
+ // to end. If there are more than one with the same highest refresh rate, the first one is
+ // returned.
+ template <typename Iter>
+ const RefreshRate* getBestRefreshRate(Iter begin, Iter end) const;
+
// The list of refresh rates, indexed by display config ID. This must not change after this
// object is initialized.
AllRefreshRatesMapType mRefreshRates;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 331c8a8..71ac90e 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -230,6 +230,11 @@
mConnections[handle].thread->onConfigChanged(displayId, configId, vsyncPeriod);
}
+size_t Scheduler::getEventThreadConnectionCount(ConnectionHandle handle) {
+ RETURN_IF_INVALID_HANDLE(handle, 0);
+ return mConnections[handle].thread->getEventThreadConnectionCount();
+}
+
void Scheduler::dump(ConnectionHandle handle, std::string& result) const {
RETURN_IF_INVALID_HANDLE(handle);
mConnections.at(handle).thread->dump(result);
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 82b78e3..81051be 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -145,6 +145,8 @@
// Notifies the scheduler when the display size has changed. Called from SF's main thread
void onPrimaryDisplayAreaChanged(uint32_t displayArea);
+ size_t getEventThreadConnectionCount(ConnectionHandle handle);
+
private:
friend class TestableScheduler;
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index b467f24..399da19 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -53,15 +53,15 @@
}
inline size_t VSyncPredictor::next(int i) const {
- return (i + 1) % timestamps.size();
+ return (i + 1) % mTimestamps.size();
}
bool VSyncPredictor::validate(nsecs_t timestamp) const {
- if (lastTimestampIndex < 0 || timestamps.empty()) {
+ if (mLastTimestampIndex < 0 || mTimestamps.empty()) {
return true;
}
- auto const aValidTimestamp = timestamps[lastTimestampIndex];
+ auto const aValidTimestamp = mTimestamps[mLastTimestampIndex];
auto const percent = (timestamp - aValidTimestamp) % mIdealPeriod * kMaxPercent / mIdealPeriod;
return percent < kOutlierTolerancePercent || percent > (kMaxPercent - kOutlierTolerancePercent);
}
@@ -79,15 +79,15 @@
return false;
}
- if (timestamps.size() != kHistorySize) {
- timestamps.push_back(timestamp);
- lastTimestampIndex = next(lastTimestampIndex);
+ if (mTimestamps.size() != kHistorySize) {
+ mTimestamps.push_back(timestamp);
+ mLastTimestampIndex = next(mLastTimestampIndex);
} else {
- lastTimestampIndex = next(lastTimestampIndex);
- timestamps[lastTimestampIndex] = timestamp;
+ mLastTimestampIndex = next(mLastTimestampIndex);
+ mTimestamps[mLastTimestampIndex] = timestamp;
}
- if (timestamps.size() < kMinimumSamplesForPrediction) {
+ if (mTimestamps.size() < kMinimumSamplesForPrediction) {
mRateMap[mIdealPeriod] = {mIdealPeriod, 0};
return true;
}
@@ -107,11 +107,11 @@
//
// intercept = mean(Y) - slope * mean(X)
//
- std::vector<nsecs_t> vsyncTS(timestamps.size());
- std::vector<nsecs_t> ordinals(timestamps.size());
+ std::vector<nsecs_t> vsyncTS(mTimestamps.size());
+ std::vector<nsecs_t> ordinals(mTimestamps.size());
// normalizing to the oldest timestamp cuts down on error in calculating the intercept.
- auto const oldest_ts = *std::min_element(timestamps.begin(), timestamps.end());
+ auto const oldest_ts = *std::min_element(mTimestamps.begin(), mTimestamps.end());
auto it = mRateMap.find(mIdealPeriod);
auto const currentPeriod = std::get<0>(it->second);
// TODO (b/144707443): its important that there's some precision in the mean of the ordinals
@@ -120,10 +120,10 @@
// scheduler::utils::calculate_mean to have a fixed point fractional part.
static constexpr int kScalingFactor = 10;
- for (auto i = 0u; i < timestamps.size(); i++) {
- traceInt64If("VSP-ts", timestamps[i]);
+ for (auto i = 0u; i < mTimestamps.size(); i++) {
+ traceInt64If("VSP-ts", mTimestamps[i]);
- vsyncTS[i] = timestamps[i] - oldest_ts;
+ vsyncTS[i] = mTimestamps[i] - oldest_ts;
ordinals[i] = ((vsyncTS[i] + (currentPeriod / 2)) / currentPeriod) * kScalingFactor;
}
@@ -143,12 +143,20 @@
if (CC_UNLIKELY(bottom == 0)) {
it->second = {mIdealPeriod, 0};
+ clearTimestamps();
return false;
}
nsecs_t const anticipatedPeriod = top / bottom * kScalingFactor;
nsecs_t const intercept = meanTS - (anticipatedPeriod * meanOrdinal / kScalingFactor);
+ auto const percent = std::abs(anticipatedPeriod - mIdealPeriod) * kMaxPercent / mIdealPeriod;
+ if (percent >= kOutlierTolerancePercent) {
+ it->second = {mIdealPeriod, 0};
+ clearTimestamps();
+ return false;
+ }
+
traceInt64If("VSP-period", anticipatedPeriod);
traceInt64If("VSP-intercept", intercept);
@@ -164,14 +172,14 @@
auto const [slope, intercept] = getVSyncPredictionModel(lk);
- if (timestamps.empty()) {
+ if (mTimestamps.empty()) {
traceInt64If("VSP-mode", 1);
auto const knownTimestamp = mKnownTimestamp ? *mKnownTimestamp : timePoint;
auto const numPeriodsOut = ((timePoint - knownTimestamp) / mIdealPeriod) + 1;
return knownTimestamp + numPeriodsOut * mIdealPeriod;
}
- auto const oldest = *std::min_element(timestamps.begin(), timestamps.end());
+ auto const oldest = *std::min_element(mTimestamps.begin(), mTimestamps.end());
// See b/145667109, the ordinal calculation must take into account the intercept.
auto const zeroPoint = oldest + intercept;
@@ -225,10 +233,10 @@
}
void VSyncPredictor::clearTimestamps() {
- if (!timestamps.empty()) {
- mKnownTimestamp = *std::max_element(timestamps.begin(), timestamps.end());
- timestamps.clear();
- lastTimestampIndex = 0;
+ if (!mTimestamps.empty()) {
+ mKnownTimestamp = *std::max_element(mTimestamps.begin(), mTimestamps.end());
+ mTimestamps.clear();
+ mLastTimestampIndex = 0;
}
}
@@ -236,11 +244,11 @@
using namespace std::literals::chrono_literals;
std::lock_guard<std::mutex> lk(mMutex);
bool needsMoreSamples = true;
- if (timestamps.size() >= kMinimumSamplesForPrediction) {
+ if (mTimestamps.size() >= kMinimumSamplesForPrediction) {
nsecs_t constexpr aLongTime =
std::chrono::duration_cast<std::chrono::nanoseconds>(500ms).count();
- if (!(lastTimestampIndex < 0 || timestamps.empty())) {
- auto const lastTimestamp = timestamps[lastTimestampIndex];
+ if (!(mLastTimestampIndex < 0 || mTimestamps.empty())) {
+ auto const lastTimestamp = mTimestamps[mLastTimestampIndex];
needsMoreSamples = !((lastTimestamp + aLongTime) > now);
}
}
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h
index 532fe9e..ef1d88a 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.h
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h
@@ -83,8 +83,8 @@
std::unordered_map<nsecs_t, std::tuple<nsecs_t, nsecs_t>> mutable mRateMap GUARDED_BY(mMutex);
- int lastTimestampIndex GUARDED_BY(mMutex) = 0;
- std::vector<nsecs_t> timestamps GUARDED_BY(mMutex);
+ int mLastTimestampIndex GUARDED_BY(mMutex) = 0;
+ std::vector<nsecs_t> mTimestamps GUARDED_BY(mMutex);
};
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index da73e4e..949ba4c 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -98,6 +98,9 @@
{
std::lock_guard<std::mutex> lk(mMutex);
+ if (mStopped) {
+ return;
+ }
auto const schedule_result = mRegistration.schedule(calculateWorkload(), vsynctime);
LOG_ALWAYS_FATAL_IF((schedule_result != ScheduleResult::Scheduled),
"Error rescheduling callback: rc %X", schedule_result);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f81179a..a98ff4f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -57,6 +57,7 @@
#include <gui/IDisplayEventConnection.h>
#include <gui/IProducerListener.h>
#include <gui/LayerDebugInfo.h>
+#include <gui/LayerMetadata.h>
#include <gui/Surface.h>
#include <input/IInputFlinger.h>
#include <renderengine/RenderEngine.h>
@@ -83,10 +84,10 @@
#include "BufferQueueLayer.h"
#include "BufferStateLayer.h"
#include "Client.h"
-#include "ColorLayer.h"
#include "Colorizer.h"
#include "ContainerLayer.h"
#include "DisplayDevice.h"
+#include "EffectLayer.h"
#include "Layer.h"
#include "LayerVector.h"
#include "MonitoredProducer.h"
@@ -622,7 +623,7 @@
LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
"Starting with vr flinger active is not currently supported.");
mCompositionEngine->setHwComposer(getFactory().createHWComposer(getBE().mHwcServiceName));
- mCompositionEngine->getHwComposer().registerCallback(this, getBE().mComposerSequenceId);
+ mCompositionEngine->getHwComposer().setConfiguration(this, getBE().mComposerSequenceId);
// Process any initial hotplug and resulting display changes.
processDisplayHotplugEventsLocked();
const auto display = getDefaultDisplayDeviceLocked();
@@ -782,14 +783,18 @@
return NAME_NOT_FOUND;
}
- if (display->isVirtual()) {
+ if (const auto connectionType = display->getConnectionType())
+ info->connectionType = *connectionType;
+ else {
return INVALID_OPERATION;
}
if (mEmulatedDisplayDensity) {
info->density = mEmulatedDisplayDensity;
} else {
- info->density = display->isPrimary() ? mInternalDisplayDensity : FALLBACK_DENSITY;
+ info->density = info->connectionType == DisplayConnectionType::Internal
+ ? mInternalDisplayDensity
+ : FALLBACK_DENSITY;
}
info->secure = display->isSecure();
@@ -1682,7 +1687,7 @@
mCompositionEngine->setHwComposer(std::unique_ptr<HWComposer>());
mCompositionEngine->setHwComposer(getFactory().createHWComposer(
vrFlingerRequestsDisplay ? "vr" : getBE().mHwcServiceName));
- getHwComposer().registerCallback(this, ++getBE().mComposerSequenceId);
+ mCompositionEngine->getHwComposer().setConfiguration(this, ++getBE().mComposerSequenceId);
LOG_ALWAYS_FATAL_IF(!getHwComposer().getComposer()->isRemote(),
"Switched to non-remote hardware composer");
@@ -2081,7 +2086,8 @@
}
});
- if (presentFenceTime->isValid()) {
+ if (displayDevice && displayDevice->isPrimary() &&
+ displayDevice->getPowerMode() == HWC_POWER_MODE_NORMAL && presentFenceTime->isValid()) {
mScheduler->addPresentFence(presentFenceTime);
}
@@ -2119,6 +2125,10 @@
mTimeStats->setPresentFenceGlobal(presentFenceTime);
+ const size_t sfConnections = mScheduler->getEventThreadConnectionCount(mSfConnectionHandle);
+ const size_t appConnections = mScheduler->getEventThreadConnectionCount(mAppConnectionHandle);
+ mTimeStats->recordDisplayEventConnectionCount(sfConnections + appConnections);
+
if (displayDevice && getHwComposer().isConnected(*displayDevice->getId()) &&
!displayDevice->isPoweredOn()) {
return;
@@ -2236,30 +2246,38 @@
continue;
}
+ const DisplayId displayId = info->id;
+ const auto it = mPhysicalDisplayTokens.find(displayId);
+
if (event.connection == HWC2::Connection::Connected) {
- if (!mPhysicalDisplayTokens.count(info->id)) {
- ALOGV("Creating display %s", to_string(info->id).c_str());
+ if (it == mPhysicalDisplayTokens.end()) {
+ ALOGV("Creating display %s", to_string(displayId).c_str());
+
if (event.hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) {
- initScheduler(info->id);
+ initScheduler(displayId);
}
- mPhysicalDisplayTokens[info->id] = new BBinder();
+
DisplayDeviceState state;
- state.displayId = info->id;
+ state.physical = {displayId, getHwComposer().getDisplayConnectionType(displayId)};
state.isSecure = true; // All physical displays are currently considered secure.
state.displayName = info->name;
- mCurrentState.displays.add(mPhysicalDisplayTokens[info->id], state);
+
+ sp<IBinder> token = new BBinder();
+ mCurrentState.displays.add(token, state);
+ mPhysicalDisplayTokens.emplace(displayId, std::move(token));
+
mInterceptor->saveDisplayCreation(state);
}
} else {
- ALOGV("Removing display %s", to_string(info->id).c_str());
+ ALOGV("Removing display %s", to_string(displayId).c_str());
- ssize_t index = mCurrentState.displays.indexOfKey(mPhysicalDisplayTokens[info->id]);
+ const ssize_t index = mCurrentState.displays.indexOfKey(it->second);
if (index >= 0) {
const DisplayDeviceState& state = mCurrentState.displays.valueAt(index);
mInterceptor->saveDisplayDeletion(state.sequenceId);
mCurrentState.displays.removeItemsAt(index);
}
- mPhysicalDisplayTokens.erase(info->id);
+ mPhysicalDisplayTokens.erase(it);
}
processDisplayChangesLocked();
@@ -2279,13 +2297,16 @@
const sp<IGraphicBufferProducer>& producer) {
DisplayDeviceCreationArgs creationArgs(this, displayToken, displayId);
creationArgs.sequenceId = state.sequenceId;
- creationArgs.isVirtual = state.isVirtual();
creationArgs.isSecure = state.isSecure;
creationArgs.displaySurface = dispSurface;
creationArgs.hasWideColorGamut = false;
creationArgs.supportedPerFrameMetadata = 0;
creationArgs.powerAdvisor = displayId ? &mPowerAdvisor : nullptr;
+ if (const auto& physical = state.physical) {
+ creationArgs.connectionType = physical->type;
+ }
+
const bool isInternalDisplay = displayId && displayId == getInternalDisplayIdLocked();
creationArgs.isPrimary = isInternalDisplay;
@@ -2476,8 +2497,8 @@
"surface is provided (%p), ignoring it",
state.surface.get());
- displayId = state.displayId;
- LOG_ALWAYS_FATAL_IF(!displayId);
+ LOG_FATAL_IF(!state.physical);
+ displayId = state.physical->id;
dispSurface = new FramebufferSurface(getHwComposer(), *displayId, bqConsumer);
producer = bqProducer;
}
@@ -3695,7 +3716,7 @@
result = createBufferStateLayer(client, std::move(uniqueName), w, h, flags,
std::move(metadata), handle, outTransformHint, &layer);
break;
- case ISurfaceComposerClient::eFXSurfaceColor:
+ case ISurfaceComposerClient::eFXSurfaceEffect:
// check if buffer size is set for color layer.
if (w > 0 || h > 0) {
ALOGE("createLayer() failed, w or h cannot be set for color layer (w=%d, h=%d)",
@@ -3703,8 +3724,8 @@
return BAD_VALUE;
}
- result = createColorLayer(client, std::move(uniqueName), w, h, flags,
- std::move(metadata), handle, &layer);
+ result = createEffectLayer(client, std::move(uniqueName), w, h, flags,
+ std::move(metadata), handle, &layer);
break;
case ISurfaceComposerClient::eFXSurfaceContainer:
// check if buffer size is set for container layer.
@@ -3822,10 +3843,10 @@
return NO_ERROR;
}
-status_t SurfaceFlinger::createColorLayer(const sp<Client>& client, std::string name, uint32_t w,
- uint32_t h, uint32_t flags, LayerMetadata metadata,
- sp<IBinder>* handle, sp<Layer>* outLayer) {
- *outLayer = getFactory().createColorLayer(
+status_t SurfaceFlinger::createEffectLayer(const sp<Client>& client, std::string name, uint32_t w,
+ uint32_t h, uint32_t flags, LayerMetadata metadata,
+ sp<IBinder>* handle, sp<Layer>* outLayer) {
+ *outLayer = getFactory().createEffectLayer(
{this, client, std::move(name), w, h, flags, std::move(metadata)});
*handle = (*outLayer)->getHandle();
return NO_ERROR;
@@ -5546,17 +5567,18 @@
renderArea.isSecure(),
supportProtectedContent,
clearRegion,
+ displayViewport,
+ clientCompositionDisplay.outputDataspace,
+ true, /* realContentIsVisible */
+ false, /* clearContent */
};
- auto result = layer->prepareClientComposition(targetSettings);
- if (result) {
- std::optional<compositionengine::LayerFE::LayerSettings> shadowLayer =
- layer->prepareShadowClientComposition(*result, displayViewport,
- clientCompositionDisplay.outputDataspace);
- if (shadowLayer) {
- clientCompositionLayers.push_back(*shadowLayer);
- }
- clientCompositionLayers.push_back(*result);
- }
+ std::vector<compositionengine::LayerFE::LayerSettings> results =
+ layer->prepareClientCompositionList(targetSettings);
+ clientCompositionLayers.insert(clientCompositionLayers.end(),
+ std::make_move_iterator(results.begin()),
+ std::make_move_iterator(results.end()));
+ results.clear();
+
});
std::vector<const renderengine::LayerSettings*> clientCompositionLayerPointers;
@@ -5850,6 +5872,21 @@
return NO_ERROR;
}
+const std::unordered_map<std::string, uint32_t>& SurfaceFlinger::getGenericLayerMetadataKeyMap()
+ const {
+ // TODO(b/149500060): Remove this fixed/static mapping. Please prefer taking
+ // on the work to remove the table in that bug rather than adding more to
+ // it.
+ static const std::unordered_map<std::string, uint32_t> genericLayerMetadataKeyMap{
+ // Note: METADATA_OWNER_UID and METADATA_WINDOW_TYPE are officially
+ // supported, and exposed via the
+ // IVrComposerClient::VrCommand::SET_LAYER_INFO command.
+ {"org.chromium.arc.V1_0.TaskId", METADATA_TASK_ID},
+ {"org.chromium.arc.V1_0.CursorInfo", METADATA_MOUSE_CURSOR},
+ };
+ return genericLayerMetadataKeyMap;
+}
+
} // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 8cabcf0..0144b4e 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -653,9 +653,9 @@
sp<IBinder>* outHandle, uint32_t* outTransformHint,
sp<Layer>* outLayer);
- status_t createColorLayer(const sp<Client>& client, std::string name, uint32_t w, uint32_t h,
- uint32_t flags, LayerMetadata metadata, sp<IBinder>* outHandle,
- sp<Layer>* outLayer);
+ status_t createEffectLayer(const sp<Client>& client, std::string name, uint32_t w, uint32_t h,
+ uint32_t flags, LayerMetadata metadata, sp<IBinder>* outHandle,
+ sp<Layer>* outLayer);
status_t createContainerLayer(const sp<Client>& client, std::string name, uint32_t w,
uint32_t h, uint32_t flags, LayerMetadata metadata,
@@ -1153,6 +1153,15 @@
std::atomic<nsecs_t> mExpectedPresentTime = 0;
+ /* ------------------------------------------------------------------------
+ * Generic Layer Metadata
+ */
+ const std::unordered_map<std::string, uint32_t>& getGenericLayerMetadataKeyMap() const;
+
+ /* ------------------------------------------------------------------------
+ * Misc
+ */
+
std::mutex mActiveConfigLock;
// This bit is set once we start setting the config. We read from this bit during the
// process. If at the end, this bit is different than mDesiredActiveConfig, we restart
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index f9658a7..d49133d 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -25,9 +25,9 @@
#include "BufferLayerConsumer.h"
#include "BufferQueueLayer.h"
#include "BufferStateLayer.h"
-#include "ColorLayer.h"
#include "ContainerLayer.h"
#include "DisplayDevice.h"
+#include "EffectLayer.h"
#include "Layer.h"
#include "MonitoredProducer.h"
#include "NativeWindowSurface.h"
@@ -139,8 +139,8 @@
return new BufferStateLayer(args);
}
-sp<ColorLayer> DefaultFactory::createColorLayer(const LayerCreationArgs& args) {
- return new ColorLayer(args);
+sp<EffectLayer> DefaultFactory::createEffectLayer(const LayerCreationArgs& args) {
+ return new EffectLayer(args);
}
} // namespace android::surfaceflinger
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
index 36fae21..89194c7 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -55,7 +55,7 @@
std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine() override;
sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs& args) override;
sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) override;
- sp<ColorLayer> createColorLayer(const LayerCreationArgs& args) override;
+ sp<EffectLayer> createEffectLayer(const LayerCreationArgs& args) override;
sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) override;
};
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index 951bd09..209bd0c 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -16,14 +16,14 @@
#pragma once
+#include <cutils/compiler.h>
+#include <utils/StrongPointer.h>
+
#include <cinttypes>
#include <functional>
#include <memory>
#include <string>
-#include <cutils/compiler.h>
-#include <utils/StrongPointer.h>
-
namespace android {
typedef int32_t PixelFormat;
@@ -31,7 +31,7 @@
class BufferQueueLayer;
class BufferStateLayer;
class BufferLayerConsumer;
-class ColorLayer;
+class EffectLayer;
class ContainerLayer;
class DisplayDevice;
class DispSync;
@@ -104,7 +104,7 @@
virtual sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs& args) = 0;
virtual sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) = 0;
- virtual sp<ColorLayer> createColorLayer(const LayerCreationArgs& args) = 0;
+ virtual sp<EffectLayer> createEffectLayer(const LayerCreationArgs& args) = 0;
virtual sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) = 0;
protected:
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 6884b4c..1f9d46c 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -595,8 +595,8 @@
creation->set_id(info.sequenceId);
creation->set_name(info.displayName);
creation->set_is_secure(info.isSecure);
- if (info.displayId) {
- creation->set_display_id(info.displayId->value);
+ if (info.physical) {
+ creation->set_display_id(info.physical->id.value);
}
}
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index b2cce7c..8038eba 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -55,27 +55,6 @@
return result;
}
-AStatsManager_PullAtomCallbackReturn TimeStats::populateGlobalAtom(AStatsEventList* data) {
- std::lock_guard<std::mutex> lock(mMutex);
-
- if (mTimeStats.statsStart == 0) {
- return AStatsManager_PULL_SKIP;
- }
- flushPowerTimeLocked();
-
- AStatsEvent* event = mStatsDelegate->addStatsEventToPullData(data);
- mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
- mStatsDelegate->statsEventWriteInt64(event, mTimeStats.totalFrames);
- mStatsDelegate->statsEventWriteInt64(event, mTimeStats.missedFrames);
- mStatsDelegate->statsEventWriteInt64(event, mTimeStats.clientCompositionFrames);
- mStatsDelegate->statsEventWriteInt64(event, mTimeStats.displayOnTime);
- mStatsDelegate->statsEventWriteInt64(event, mTimeStats.presentToPresent.totalTime());
- mStatsDelegate->statsEventBuild(event);
- clearGlobalLocked();
-
- return AStatsManager_PULL_SUCCESS;
-}
-
namespace {
// Histograms align with the order of fields in SurfaceflingerStatsLayerInfo.
const std::array<std::string, 6> kHistogramNames = {
@@ -111,6 +90,37 @@
}
} // namespace
+AStatsManager_PullAtomCallbackReturn TimeStats::populateGlobalAtom(AStatsEventList* data) {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ if (mTimeStats.statsStart == 0) {
+ return AStatsManager_PULL_SKIP;
+ }
+ flushPowerTimeLocked();
+
+ AStatsEvent* event = mStatsDelegate->addStatsEventToPullData(data);
+ mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
+ mStatsDelegate->statsEventWriteInt64(event, mTimeStats.totalFrames);
+ mStatsDelegate->statsEventWriteInt64(event, mTimeStats.missedFrames);
+ mStatsDelegate->statsEventWriteInt64(event, mTimeStats.clientCompositionFrames);
+ mStatsDelegate->statsEventWriteInt64(event, mTimeStats.displayOnTime);
+ mStatsDelegate->statsEventWriteInt64(event, mTimeStats.presentToPresent.totalTime());
+ mStatsDelegate->statsEventWriteInt32(event, mTimeStats.displayEventConnectionsCount);
+ std::string frameDurationBytes =
+ histogramToProtoByteString(mTimeStats.frameDuration.hist, mMaxPulledHistogramBuckets);
+ mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)frameDurationBytes.c_str(),
+ frameDurationBytes.size());
+ std::string renderEngineTimingBytes =
+ histogramToProtoByteString(mTimeStats.renderEngineTiming.hist,
+ mMaxPulledHistogramBuckets);
+ mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)renderEngineTimingBytes.c_str(),
+ renderEngineTimingBytes.size());
+ mStatsDelegate->statsEventBuild(event);
+ clearGlobalLocked();
+
+ return AStatsManager_PULL_SUCCESS;
+}
+
AStatsManager_PullAtomCallbackReturn TimeStats::populateLayerAtom(AStatsEventList* data) {
std::lock_guard<std::mutex> lock(mMutex);
@@ -272,6 +282,16 @@
mTimeStats.clientCompositionReusedFrames++;
}
+void TimeStats::recordDisplayEventConnectionCount(int32_t count) {
+ if (!mEnabled.load()) return;
+
+ ATRACE_CALL();
+
+ std::lock_guard<std::mutex> lock(mMutex);
+ mTimeStats.displayEventConnectionsCount =
+ std::max(mTimeStats.displayEventConnectionsCount, count);
+}
+
static int32_t msBetween(nsecs_t start, nsecs_t end) {
int64_t delta = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::nanoseconds(end - start))
@@ -815,6 +835,7 @@
mTimeStats.missedFrames = 0;
mTimeStats.clientCompositionFrames = 0;
mTimeStats.clientCompositionReusedFrames = 0;
+ mTimeStats.displayEventConnectionsCount = 0;
mTimeStats.displayOnTime = 0;
mTimeStats.presentToPresent.hist.clear();
mTimeStats.frameDuration.hist.clear();
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index a428ef4..ddebeb1 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -52,6 +52,9 @@
virtual void incrementMissedFrames() = 0;
virtual void incrementClientCompositionFrames() = 0;
virtual void incrementClientCompositionReusedFrames() = 0;
+ // Records the most up-to-date count of display event connections.
+ // The stored count will be the maximum ever recoded.
+ virtual void recordDisplayEventConnectionCount(int32_t count) = 0;
// Records the start and end times for a frame.
// The start time is the same as the beginning of a SurfaceFlinger
@@ -177,6 +180,10 @@
return AStatsEvent_setAtomId(event, atom_id);
}
+ virtual void statsEventWriteInt32(AStatsEvent* event, int32_t field) {
+ return AStatsEvent_writeInt32(event, field);
+ }
+
virtual void statsEventWriteInt64(AStatsEvent* event, int64_t field) {
return AStatsEvent_writeInt64(event, field);
}
@@ -208,6 +215,7 @@
void incrementMissedFrames() override;
void incrementClientCompositionFrames() override;
void incrementClientCompositionReusedFrames() override;
+ void recordDisplayEventConnectionCount(int32_t count) override;
void recordFrameDuration(nsecs_t startTime, nsecs_t endTime) override;
void recordRenderEngineDuration(nsecs_t startTime, nsecs_t endTime) override;
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index e374b73..5e7c449 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -62,6 +62,7 @@
int32_t missedFrames = 0;
int32_t clientCompositionFrames = 0;
int32_t clientCompositionReusedFrames = 0;
+ int32_t displayEventConnectionsCount = 0;
int64_t displayOnTime = 0;
Histogram presentToPresent;
Histogram frameDuration;
diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
index 24874b0..83e5060 100644
--- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
@@ -531,7 +531,7 @@
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
ASSERT_NO_FATAL_FAILURE(colorLayer =
createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor));
+ ISurfaceComposerClient::eFXSurfaceEffect));
Transaction()
.setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
@@ -570,7 +570,7 @@
Color priorBgColor = Color::BLUE;
Color expectedColor = Color::BLACK;
switch (layerType) {
- case ISurfaceComposerClient::eFXSurfaceColor:
+ case ISurfaceComposerClient::eFXSurfaceEffect:
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 0, 0, layerType));
Transaction()
.setCrop_legacy(layer, Rect(0, 0, width, height))
@@ -599,7 +599,7 @@
return;
}
- if (priorColor && layerType != ISurfaceComposerClient::eFXSurfaceColor) {
+ if (priorColor && layerType != ISurfaceComposerClient::eFXSurfaceEffect) {
Transaction()
.setBackgroundColor(layer, half3(0, 0, 1.0f), 1.0f, ui::Dataspace::UNKNOWN)
.apply();
@@ -628,7 +628,7 @@
bool bufferFill = false;
float alpha = 1.0f;
Color finalColor = Color::RED;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceColor,
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceEffect,
priorColor, bufferFill, alpha, finalColor));
}
@@ -744,15 +744,29 @@
sp<SurfaceControl> colorLayer;
ASSERT_NO_FATAL_FAILURE(colorLayer =
createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor));
+ ISurfaceComposerClient::eFXSurfaceEffect));
Transaction()
.setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
- .setColor(colorLayer, half3(2.0f, -1.0f, 0.0f))
+ .setColor(colorLayer, half3(2.0f, 0.0f, 0.0f))
.apply();
getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
+// An invalid color will not render a color and the layer will not be visible.
+TEST_P(LayerRenderTypeTransactionTest, SetInvalidColor) {
+ sp<SurfaceControl> colorLayer;
+ ASSERT_NO_FATAL_FAILURE(colorLayer =
+ createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceEffect));
+ Transaction()
+ .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
+ .setColor(colorLayer, half3(1.0f, -1.0f, 0.5f))
+ .apply();
+
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
TEST_P(LayerRenderTypeTransactionTest, SetColorWithAlpha) {
sp<SurfaceControl> bufferLayer;
sp<SurfaceControl> colorLayer;
@@ -760,7 +774,7 @@
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
ASSERT_NO_FATAL_FAILURE(colorLayer =
createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor));
+ ISurfaceComposerClient::eFXSurfaceEffect));
Transaction().setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)).apply();
const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
@@ -787,7 +801,7 @@
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer("childWithColor", 0 /* buffer width */,
0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor));
+ ISurfaceComposerClient::eFXSurfaceEffect));
Transaction().setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)).apply();
const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
const float alpha = 0.25f;
@@ -1663,7 +1677,7 @@
sp<SurfaceControl> colorLayer;
ASSERT_NO_FATAL_FAILURE(colorLayer =
createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor));
+ ISurfaceComposerClient::eFXSurfaceEffect));
Transaction()
.setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
.setLayer(colorLayer, mLayerZBase + 1)
@@ -1719,7 +1733,7 @@
ISurfaceComposerClient::eFXSurfaceContainer));
ASSERT_NO_FATAL_FAILURE(
colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor, parentLayer.get()));
+ ISurfaceComposerClient::eFXSurfaceEffect, parentLayer.get()));
Transaction()
.setCrop_legacy(parentLayer, Rect(0, 0, 100, 100))
@@ -1780,7 +1794,7 @@
ISurfaceComposerClient::eFXSurfaceContainer));
ASSERT_NO_FATAL_FAILURE(
colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor, parentLayer.get()));
+ ISurfaceComposerClient::eFXSurfaceEffect, parentLayer.get()));
Transaction()
.setCrop_legacy(parentLayer, Rect(0, 0, 100, 100))
diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h
index 5eb1739..932c7c8 100644
--- a/services/surfaceflinger/tests/LayerTransactionTest.h
+++ b/services/surfaceflinger/tests/LayerTransactionTest.h
@@ -89,7 +89,7 @@
SurfaceControl* parent = nullptr) {
auto colorLayer = createSurface(mClient, name, 0 /* buffer width */, 0 /* buffer height */,
PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor, parent);
+ ISurfaceComposerClient::eFXSurfaceEffect, parent);
asTransaction([&](Transaction& t) {
t.setColor(colorLayer, half3{color.r / 255.0f, color.g / 255.0f, color.b / 255.0f});
t.setAlpha(colorLayer, color.a / 255.0f);
@@ -268,7 +268,7 @@
mBlackBgSurface =
createSurface(mClient, "BaseSurface", 0 /* buffer width */, 0 /* buffer height */,
- PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor);
+ PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect);
// set layer stack (b/68888219)
Transaction t;
diff --git a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
index 7e9202b..84780ba 100644
--- a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
@@ -69,13 +69,13 @@
TEST_P(LayerTypeTransactionTest, SetLayerAndRelative) {
sp<SurfaceControl> parent =
LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor);
+ ISurfaceComposerClient::eFXSurfaceEffect);
sp<SurfaceControl> childLayer;
ASSERT_NO_FATAL_FAILURE(
childLayer = LayerTransactionTest::createLayer("childLayer", 0 /* buffer width */,
0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor,
+ ISurfaceComposerClient::eFXSurfaceEffect,
parent.get()));
Transaction()
.setColor(childLayer, half3{1.0f, 0.0f, 0.0f})
@@ -116,17 +116,17 @@
TEST_P(LayerTypeTransactionTest, HideRelativeParentHidesLayer) {
sp<SurfaceControl> parent =
LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor);
+ ISurfaceComposerClient::eFXSurfaceEffect);
sp<SurfaceControl> relativeParent =
LayerTransactionTest::createLayer("RelativeParent", 0 /* buffer width */,
0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor);
+ ISurfaceComposerClient::eFXSurfaceEffect);
sp<SurfaceControl> childLayer;
ASSERT_NO_FATAL_FAILURE(
childLayer = LayerTransactionTest::createLayer("childLayer", 0 /* buffer width */,
0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor,
+ ISurfaceComposerClient::eFXSurfaceEffect,
parent.get()));
Transaction()
.setColor(childLayer, half3{1.0f, 0.0f, 0.0f})
diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp
index a1c4128..cf3f8e8 100644
--- a/services/surfaceflinger/tests/LayerUpdate_test.cpp
+++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp
@@ -1114,7 +1114,7 @@
TEST_F(BoundlessLayerTest, BoundlessColorLayerFillsParentBufferBounds) {
sp<SurfaceControl> colorLayer =
createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor, mFGSurfaceControl.get());
+ ISurfaceComposerClient::eFXSurfaceEffect, mFGSurfaceControl.get());
ASSERT_TRUE(colorLayer->isValid());
asTransaction([&](Transaction& t) {
t.setColor(colorLayer, half3{0, 0, 0});
@@ -1139,7 +1139,7 @@
ASSERT_TRUE(cropLayer->isValid());
sp<SurfaceControl> colorLayer =
createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor, cropLayer.get());
+ ISurfaceComposerClient::eFXSurfaceEffect, cropLayer.get());
ASSERT_TRUE(colorLayer->isValid());
asTransaction([&](Transaction& t) {
t.setCrop_legacy(cropLayer, Rect(5, 5, 10, 10));
@@ -1164,7 +1164,7 @@
TEST_F(BoundlessLayerTest, BoundlessColorLayerTransformHasNoEffect) {
sp<SurfaceControl> colorLayer =
createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor, mFGSurfaceControl.get());
+ ISurfaceComposerClient::eFXSurfaceEffect, mFGSurfaceControl.get());
ASSERT_TRUE(colorLayer->isValid());
asTransaction([&](Transaction& t) {
t.setPosition(colorLayer, 320, 320);
@@ -1195,7 +1195,7 @@
ASSERT_TRUE(boundlessLayerDownShift->isValid());
sp<SurfaceControl> colorLayer =
createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor, boundlessLayerDownShift.get());
+ ISurfaceComposerClient::eFXSurfaceEffect, boundlessLayerDownShift.get());
ASSERT_TRUE(colorLayer->isValid());
asTransaction([&](Transaction& t) {
t.setPosition(boundlessLayerRightShift, 32, 0);
@@ -1229,7 +1229,7 @@
ASSERT_TRUE(boundlessLayer->isValid());
sp<SurfaceControl> colorLayer =
mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor, boundlessLayer.get());
+ ISurfaceComposerClient::eFXSurfaceEffect, boundlessLayer.get());
ASSERT_TRUE(colorLayer != nullptr);
ASSERT_TRUE(colorLayer->isValid());
asTransaction([&](Transaction& t) {
@@ -1261,7 +1261,7 @@
ASSERT_TRUE(rootBoundlessLayer->isValid());
sp<SurfaceControl> colorLayer =
createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor, rootBoundlessLayer.get());
+ ISurfaceComposerClient::eFXSurfaceEffect, rootBoundlessLayer.get());
ASSERT_TRUE(colorLayer->isValid());
asTransaction([&](Transaction& t) {
diff --git a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
index c9fdc3b..f8a5b40 100644
--- a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
+++ b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
@@ -66,7 +66,7 @@
void createColorLayer(uint32_t layerStack) {
mColorLayer =
createSurface(mClient, "ColorLayer", 0 /* buffer width */, 0 /* buffer height */,
- PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor);
+ PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect);
ASSERT_TRUE(mColorLayer != nullptr);
ASSERT_TRUE(mColorLayer->isValid());
asTransaction([&](Transaction& t) {
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index e751496..32c58ad 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -1827,10 +1827,11 @@
protected:
void SetUp() override {
Base::SetUp();
- Base::mChild = Base::mComposerClient->createSurface(String8("Child surface"), 0, 0,
- PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor,
- Base::mFGSurfaceControl.get());
+ Base::mChild =
+ Base::mComposerClient->createSurface(String8("Child surface"), 0, 0,
+ PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceEffect,
+ Base::mFGSurfaceControl.get());
{
TransactionScope ts(*Base::sFakeComposer);
ts.setColor(Base::mChild,
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index d046f76..1cd8731 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -42,6 +42,7 @@
"DisplayTransactionTest.cpp",
"EventControlThreadTest.cpp",
"EventThreadTest.cpp",
+ "HWComposerTest.cpp",
"OneShotTimerTest.cpp",
"LayerHistoryTest.cpp",
"LayerHistoryTestV2.cpp",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 888e009..06ef8e7 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -35,7 +35,7 @@
#include <utils/String8.h>
#include "BufferQueueLayer.h"
-#include "ColorLayer.h"
+#include "EffectLayer.h"
#include "Layer.h"
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
@@ -116,8 +116,6 @@
void setupComposer(int virtualDisplayCount) {
mComposer = new Hwc2::mock::Composer();
- EXPECT_CALL(*mComposer, getCapabilities())
- .WillOnce(Return(std::vector<IComposer::Capability>()));
EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
@@ -286,13 +284,14 @@
EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1);
EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1);
EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1);
- test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, DEFAULT_DISPLAY_ID,
- false /* isVirtual */, true /* isPrimary */)
- .setDisplaySurface(test->mDisplaySurface)
- .setNativeWindow(test->mNativeWindow)
- .setSecure(Derived::IS_SECURE)
- .setPowerMode(Derived::INIT_POWER_MODE)
- .inject();
+ test->mDisplay =
+ FakeDisplayDeviceInjector(test->mFlinger, DEFAULT_DISPLAY_ID,
+ DisplayConnectionType::Internal, true /* isPrimary */)
+ .setDisplaySurface(test->mDisplaySurface)
+ .setNativeWindow(test->mNativeWindow)
+ .setSecure(Derived::IS_SECURE)
+ .setPowerMode(Derived::INIT_POWER_MODE)
+ .inject();
Mock::VerifyAndClear(test->mNativeWindow);
test->mDisplay->setLayerStack(DEFAULT_LAYER_STACK);
}
@@ -713,7 +712,7 @@
struct DefaultLayerProperties : public BaseLayerProperties<DefaultLayerProperties> {};
-struct ColorLayerProperties : public BaseLayerProperties<ColorLayerProperties> {
+struct EffectLayerProperties : public BaseLayerProperties<EffectLayerProperties> {
static constexpr IComposerClient::BlendMode BLENDMODE = IComposerClient::BlendMode::NONE;
};
@@ -866,16 +865,16 @@
};
template <typename LayerProperties>
-struct ColorLayerVariant : public BaseLayerVariant<LayerProperties> {
+struct EffectLayerVariant : public BaseLayerVariant<LayerProperties> {
using Base = BaseLayerVariant<LayerProperties>;
- using FlingerLayerType = sp<ColorLayer>;
+ using FlingerLayerType = sp<EffectLayer>;
static FlingerLayerType createLayer(CompositionTest* test) {
- FlingerLayerType layer = Base::template createLayerWithFactory<ColorLayer>(test, [test]() {
- return new ColorLayer(LayerCreationArgs(test->mFlinger.mFlinger.get(), sp<Client>(),
- "test-layer", LayerProperties::WIDTH,
- LayerProperties::HEIGHT,
- LayerProperties::LAYER_FLAGS, LayerMetadata()));
+ FlingerLayerType layer = Base::template createLayerWithFactory<EffectLayer>(test, [test]() {
+ return new EffectLayer(
+ LayerCreationArgs(test->mFlinger.mFlinger.get(), sp<Client>(), "test-layer",
+ LayerProperties::WIDTH, LayerProperties::HEIGHT,
+ LayerProperties::LAYER_FLAGS, LayerMetadata()));
});
auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer);
@@ -1228,31 +1227,31 @@
* Single-color layers
*/
-TEST_F(CompositionTest, HWCComposedColorLayerWithDirtyGeometry) {
+TEST_F(CompositionTest, HWCComposedEffectLayerWithDirtyGeometry) {
displayRefreshCompositionDirtyGeometry<
- CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+ CompositionCase<DefaultDisplaySetupVariant, EffectLayerVariant<EffectLayerProperties>,
KeepCompositionTypeVariant<IComposerClient::Composition::SOLID_COLOR>,
HwcCompositionResultVariant>>();
}
-TEST_F(CompositionTest, HWCComposedColorLayerWithDirtyFrame) {
+TEST_F(CompositionTest, HWCComposedEffectLayerWithDirtyFrame) {
displayRefreshCompositionDirtyFrame<
- CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+ CompositionCase<DefaultDisplaySetupVariant, EffectLayerVariant<EffectLayerProperties>,
KeepCompositionTypeVariant<IComposerClient::Composition::SOLID_COLOR>,
HwcCompositionResultVariant>>();
}
-TEST_F(CompositionTest, REComposedColorLayer) {
+TEST_F(CompositionTest, REComposedEffectLayer) {
displayRefreshCompositionDirtyFrame<
- CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+ CompositionCase<DefaultDisplaySetupVariant, EffectLayerVariant<EffectLayerProperties>,
ChangeCompositionTypeVariant<IComposerClient::Composition::SOLID_COLOR,
IComposerClient::Composition::CLIENT>,
RECompositionResultVariant>>();
}
-TEST_F(CompositionTest, captureScreenColorLayer) {
+TEST_F(CompositionTest, captureScreenEffectLayer) {
captureScreenComposition<
- CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+ CompositionCase<DefaultDisplaySetupVariant, EffectLayerVariant<EffectLayerProperties>,
NoCompositionTypeVariant, REScreenshotResultVariant>>();
}
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index dddad92..4da0647 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -201,8 +201,6 @@
void DisplayTransactionTest::injectMockComposer(int virtualDisplayCount) {
mComposer = new Hwc2::mock::Composer();
- EXPECT_CALL(*mComposer, getCapabilities())
- .WillOnce(Return(std::vector<IComposer::Capability>()));
EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
@@ -312,6 +310,16 @@
static std::optional<DisplayId> get() { return {}; }
};
+template <typename>
+struct DisplayConnectionTypeGetter {
+ static constexpr std::optional<DisplayConnectionType> value;
+};
+
+template <typename PhysicalDisplay>
+struct DisplayConnectionTypeGetter<PhysicalDisplayId<PhysicalDisplay>> {
+ static constexpr std::optional<DisplayConnectionType> value = PhysicalDisplay::CONNECTION_TYPE;
+};
+
// DisplayIdType can be:
// 1) PhysicalDisplayId<...> for generated ID of physical display backed by HWC.
// 2) VirtualDisplayId<...> for hard-coded ID of virtual display backed by HWC.
@@ -320,6 +328,7 @@
Secure secure, Primary primary, int grallocUsage>
struct DisplayVariant {
using DISPLAY_ID = DisplayIdGetter<DisplayIdType>;
+ using CONNECTION_TYPE = DisplayConnectionTypeGetter<DisplayIdType>;
// The display width and height
static constexpr int WIDTH = width;
@@ -345,8 +354,8 @@
static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) {
auto injector =
- FakeDisplayDeviceInjector(test->mFlinger, DISPLAY_ID::get(),
- static_cast<bool>(VIRTUAL), static_cast<bool>(PRIMARY));
+ FakeDisplayDeviceInjector(test->mFlinger, DISPLAY_ID::get(), CONNECTION_TYPE::value,
+ static_cast<bool>(PRIMARY));
injector.setSecure(static_cast<bool>(SECURE));
injector.setNativeWindow(test->mNativeWindow);
@@ -450,6 +459,15 @@
}
static void setupHwcHotplugCallExpectations(DisplayTransactionTest* test) {
+ constexpr auto CONNECTION_TYPE =
+ PhysicalDisplay::CONNECTION_TYPE == DisplayConnectionType::Internal
+ ? IComposerClient::DisplayConnectionType::INTERNAL
+ : IComposerClient::DisplayConnectionType::EXTERNAL;
+
+ EXPECT_CALL(*test->mComposer, getDisplayConnectionType(HWC_DISPLAY_ID, _))
+ .WillOnce(
+ DoAll(SetArgPointee<1>(CONNECTION_TYPE), Return(Hwc2::V2_4::Error::NONE)));
+
EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_)).WillOnce(Return(Error::NONE));
EXPECT_CALL(*test->mComposer, getDisplayConfigs(HWC_DISPLAY_ID, _))
.WillOnce(DoAll(SetArgPointee<1>(std::vector<unsigned>{HWC_ACTIVE_CONFIG_ID}),
@@ -514,6 +532,7 @@
template <bool hasIdentificationData>
struct PrimaryDisplay {
+ static constexpr auto CONNECTION_TYPE = DisplayConnectionType::Internal;
static constexpr Primary PRIMARY = Primary::TRUE;
static constexpr uint8_t PORT = 255;
static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData;
@@ -522,6 +541,7 @@
template <bool hasIdentificationData>
struct ExternalDisplay {
+ static constexpr auto CONNECTION_TYPE = DisplayConnectionType::External;
static constexpr Primary PRIMARY = Primary::FALSE;
static constexpr uint8_t PORT = 254;
static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData;
@@ -1183,7 +1203,8 @@
GetBestColorModeTest()
: DisplayTransactionTest(),
- mInjector(FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID, false /* isVirtual */,
+ mInjector(FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID,
+ DisplayConnectionType::Internal,
true /* isPrimary */)) {}
void setHasWideColorGamut(bool hasWideColorGamut) { mHasWideColorGamut = hasWideColorGamut; }
@@ -1285,8 +1306,6 @@
class DisplayDeviceSetProjectionTest : public DisplayTransactionTest {
public:
static constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{777};
- static constexpr bool DEFAULT_DISPLAY_IS_VIRTUAL = false;
- static constexpr bool DEFAULT_DISPLAY_IS_PRIMARY = true;
static constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1080; // arbitrary
static constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1920; // arbitrary
@@ -1316,8 +1335,8 @@
EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64));
EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT));
- return FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID, DEFAULT_DISPLAY_IS_VIRTUAL,
- DEFAULT_DISPLAY_IS_PRIMARY)
+ return FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID,
+ DisplayConnectionType::Internal, true /* isPrimary */)
.setNativeWindow(mNativeWindow)
.setPhysicalOrientation(mPhysicalOrientation)
.inject();
@@ -1647,8 +1666,12 @@
// Invocation
DisplayDeviceState state;
- state.displayId = static_cast<bool>(Case::Display::VIRTUAL) ? std::nullopt
- : Case::Display::DISPLAY_ID::get();
+ if (const auto connectionType = Case::Display::CONNECTION_TYPE::value) {
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ state.physical = {*displayId, *connectionType};
+ }
+
state.isSecure = static_cast<bool>(Case::Display::SECURE);
auto device =
@@ -1660,6 +1683,7 @@
ASSERT_TRUE(device != nullptr);
EXPECT_EQ(Case::Display::DISPLAY_ID::get(), device->getId());
+ EXPECT_EQ(Case::Display::CONNECTION_TYPE::value, device->getConnectionType());
EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), device->isVirtual());
EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure());
EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary());
@@ -1823,21 +1847,24 @@
EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure());
EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary());
+ std::optional<DisplayDeviceState::Physical> expectedPhysical;
+ if (const auto connectionType = Case::Display::CONNECTION_TYPE::value) {
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ expectedPhysical = {*displayId, *connectionType};
+ }
+
// The display should have been set up in the current display state
ASSERT_TRUE(hasCurrentDisplayState(displayToken));
const auto& current = getCurrentDisplayState(displayToken);
EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), current.isVirtual());
- EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL) ? std::nullopt
- : Case::Display::DISPLAY_ID::get(),
- current.displayId);
+ EXPECT_EQ(expectedPhysical, current.physical);
// The display should have been set up in the drawing display state
ASSERT_TRUE(hasDrawingDisplayState(displayToken));
const auto& draw = getDrawingDisplayState(displayToken);
EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), draw.isVirtual());
- EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL) ? std::nullopt
- : Case::Display::DISPLAY_ID::get(),
- draw.displayId);
+ EXPECT_EQ(expectedPhysical, draw.physical);
}
template <typename Case>
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 61d4f47..65b3e35 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -19,9 +19,7 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-
#include <log/log.h>
-
#include <utils/Errors.h>
#include "AsyncCallRecorder.h"
@@ -401,6 +399,34 @@
expectVSyncSetEnabledCallReceived(false);
}
+TEST_F(EventThreadTest, tracksEventConnections) {
+ EXPECT_EQ(1, mThread->getEventThreadConnectionCount());
+ ConnectionEventRecorder errorConnectionEventRecorder{NO_MEMORY};
+ sp<MockEventThreadConnection> errorConnection =
+ createConnection(errorConnectionEventRecorder,
+ ISurfaceComposer::eConfigChangedSuppress);
+ mThread->setVsyncRate(1, errorConnection);
+ EXPECT_EQ(2, mThread->getEventThreadConnectionCount());
+ ConnectionEventRecorder secondConnectionEventRecorder{0};
+ sp<MockEventThreadConnection> secondConnection =
+ createConnection(secondConnectionEventRecorder,
+ ISurfaceComposer::eConfigChangedSuppress);
+ mThread->setVsyncRate(1, secondConnection);
+ EXPECT_EQ(3, mThread->getEventThreadConnectionCount());
+
+ // EventThread should enable vsync callbacks.
+ expectVSyncSetEnabledCallReceived(true);
+
+ // The first event will be seen by the interceptor, and by the connection,
+ // which then returns an error.
+ mCallback->onVSyncEvent(123);
+ expectInterceptCallReceived(123);
+ expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
+ expectVsyncEventReceivedByConnection("successConnection", secondConnectionEventRecorder, 123,
+ 1u);
+ EXPECT_EQ(2, mThread->getEventThreadConnectionCount());
+}
+
TEST_F(EventThreadTest, eventsDroppedIfNonfatalEventDeliveryError) {
ConnectionEventRecorder errorConnectionEventRecorder{WOULD_BLOCK};
sp<MockEventThreadConnection> errorConnection =
diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
new file mode 100644
index 0000000..c6fe205
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2020 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include <vector>
+
+#include <gmock/gmock.h>
+#include <gui/LayerMetadata.h>
+#include <log/log.h>
+
+#include "DisplayHardware/HWComposer.h"
+#include "mock/DisplayHardware/MockComposer.h"
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
+
+namespace android {
+namespace {
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::ElementsAreArray;
+using ::testing::Return;
+using ::testing::SetArgPointee;
+using ::testing::StrictMock;
+
+struct MockHWC2ComposerCallback : public HWC2::ComposerCallback {
+ ~MockHWC2ComposerCallback() = default;
+
+ MOCK_METHOD3(onHotplugReceived,
+ void(int32_t sequenceId, hwc2_display_t display, HWC2::Connection connection));
+ MOCK_METHOD2(onRefreshReceived, void(int32_t sequenceId, hwc2_display_t display));
+ MOCK_METHOD4(onVsyncReceived,
+ void(int32_t sequenceId, hwc2_display_t display, int64_t timestamp,
+ std::optional<hwc2_vsync_period_t> vsyncPeriod));
+ MOCK_METHOD3(onVsyncPeriodTimingChangedReceived,
+ void(int32_t sequenceId, hwc2_display_t display,
+ const hwc_vsync_period_change_timeline_t& updatedTimeline));
+ MOCK_METHOD2(onSeamlessPossible, void(int32_t sequenceId, hwc2_display_t display));
+};
+
+struct HWComposerTest : public testing::Test {
+ Hwc2::mock::Composer* mHal = new StrictMock<Hwc2::mock::Composer>();
+};
+
+struct HWComposerSetConfigurationTest : public HWComposerTest {
+ StrictMock<MockHWC2ComposerCallback> mCallback;
+};
+
+TEST_F(HWComposerSetConfigurationTest, loadsLayerMetadataSupport) {
+ const std::string kMetadata1Name = "com.example.metadata.1";
+ constexpr bool kMetadata1Mandatory = false;
+ const std::string kMetadata2Name = "com.example.metadata.2";
+ constexpr bool kMetadata2Mandatory = true;
+
+ EXPECT_CALL(*mHal, getMaxVirtualDisplayCount()).WillOnce(Return(0));
+ EXPECT_CALL(*mHal, getCapabilities())
+ .WillOnce(Return(std::vector<Hwc2::IComposer::Capability>{}));
+ EXPECT_CALL(*mHal, getLayerGenericMetadataKeys(_))
+ .WillOnce(DoAll(SetArgPointee<0>(
+ std::vector<Hwc2::IComposerClient::LayerGenericMetadataKey>{
+ {kMetadata1Name, kMetadata1Mandatory},
+ {kMetadata2Name, kMetadata2Mandatory},
+ }),
+ Return(hardware::graphics::composer::V2_4::Error::NONE)));
+ EXPECT_CALL(*mHal, registerCallback(_));
+ EXPECT_CALL(*mHal, isVsyncPeriodSwitchSupported()).WillOnce(Return(false));
+
+ impl::HWComposer hwc{std::unique_ptr<Hwc2::Composer>(mHal)};
+ hwc.setConfiguration(&mCallback, 123);
+
+ const auto& supported = hwc.getSupportedLayerGenericMetadata();
+ EXPECT_EQ(2u, supported.size());
+ EXPECT_EQ(1u, supported.count(kMetadata1Name));
+ EXPECT_EQ(kMetadata1Mandatory, supported.find(kMetadata1Name)->second);
+ EXPECT_EQ(1u, supported.count(kMetadata2Name));
+ EXPECT_EQ(kMetadata2Mandatory, supported.find(kMetadata2Name)->second);
+}
+
+TEST_F(HWComposerSetConfigurationTest, handlesUnsupportedCallToGetLayerGenericMetadataKeys) {
+ EXPECT_CALL(*mHal, getMaxVirtualDisplayCount()).WillOnce(Return(0));
+ EXPECT_CALL(*mHal, getCapabilities())
+ .WillOnce(Return(std::vector<Hwc2::IComposer::Capability>{}));
+ EXPECT_CALL(*mHal, getLayerGenericMetadataKeys(_))
+ .WillOnce(Return(hardware::graphics::composer::V2_4::Error::UNSUPPORTED));
+ EXPECT_CALL(*mHal, registerCallback(_));
+ EXPECT_CALL(*mHal, isVsyncPeriodSwitchSupported()).WillOnce(Return(false));
+
+ impl::HWComposer hwc{std::unique_ptr<Hwc2::Composer>(mHal)};
+ hwc.setConfiguration(&mCallback, 123);
+
+ const auto& supported = hwc.getSupportedLayerGenericMetadata();
+ EXPECT_EQ(0u, supported.size());
+}
+
+struct HWComposerLayerTest : public testing::Test {
+ static constexpr hwc2_display_t kDisplayId = static_cast<hwc2_display_t>(1001);
+ static constexpr hwc2_layer_t kLayerId = static_cast<hwc2_layer_t>(1002);
+
+ HWComposerLayerTest(const std::unordered_set<HWC2::Capability>& capabilities)
+ : mCapabilies(capabilities) {}
+
+ ~HWComposerLayerTest() override { EXPECT_CALL(*mHal, destroyLayer(kDisplayId, kLayerId)); }
+
+ std::unique_ptr<Hwc2::mock::Composer> mHal{new StrictMock<Hwc2::mock::Composer>()};
+ const std::unordered_set<HWC2::Capability> mCapabilies;
+ HWC2::impl::Layer mLayer{*mHal, mCapabilies, kDisplayId, kLayerId};
+};
+
+struct HWComposerLayerGenericMetadataTest : public HWComposerLayerTest {
+ static const std::string kLayerGenericMetadata1Name;
+ static constexpr bool kLayerGenericMetadata1Mandatory = false;
+ static const std::vector<uint8_t> kLayerGenericMetadata1Value;
+ static const std::string kLayerGenericMetadata2Name;
+ static constexpr bool kLayerGenericMetadata2Mandatory = true;
+ static const std::vector<uint8_t> kLayerGenericMetadata2Value;
+
+ HWComposerLayerGenericMetadataTest() : HWComposerLayerTest({}) {}
+};
+
+const std::string HWComposerLayerGenericMetadataTest::kLayerGenericMetadata1Name =
+ "com.example.metadata.1";
+
+const std::vector<uint8_t> HWComposerLayerGenericMetadataTest::kLayerGenericMetadata1Value = {1u,
+ 2u,
+ 3u};
+
+const std::string HWComposerLayerGenericMetadataTest::kLayerGenericMetadata2Name =
+ "com.example.metadata.2";
+
+const std::vector<uint8_t> HWComposerLayerGenericMetadataTest::kLayerGenericMetadata2Value = {45u,
+ 67u};
+
+TEST_F(HWComposerLayerGenericMetadataTest, forwardsSupportedMetadata) {
+ EXPECT_CALL(*mHal,
+ setLayerGenericMetadata(kDisplayId, kLayerId, kLayerGenericMetadata1Name,
+ kLayerGenericMetadata1Mandatory,
+ kLayerGenericMetadata1Value))
+ .WillOnce(Return(hardware::graphics::composer::V2_4::Error::NONE));
+ auto result = mLayer.setLayerGenericMetadata(kLayerGenericMetadata1Name,
+ kLayerGenericMetadata1Mandatory,
+ kLayerGenericMetadata1Value);
+ EXPECT_EQ(HWC2::Error::None, result);
+
+ EXPECT_CALL(*mHal,
+ setLayerGenericMetadata(kDisplayId, kLayerId, kLayerGenericMetadata2Name,
+ kLayerGenericMetadata2Mandatory,
+ kLayerGenericMetadata2Value))
+ .WillOnce(Return(hardware::graphics::composer::V2_4::Error::UNSUPPORTED));
+ result = mLayer.setLayerGenericMetadata(kLayerGenericMetadata2Name,
+ kLayerGenericMetadata2Mandatory,
+ kLayerGenericMetadata2Value);
+ EXPECT_EQ(HWC2::Error::Unsupported, result);
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 841c624..99c5f3d 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -745,6 +745,44 @@
}
}
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_Multiples) {
+ std::vector<RefreshRateConfigs::InputConfig> configs{
+ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
+ {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
+ RefreshRate expected90Config = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", 90};
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
+ LayerRequirement{.weight = 1.0f}};
+ auto& lr1 = layers[0];
+ auto& lr2 = layers[1];
+
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.desiredRefreshRate = 60.0f;
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.desiredRefreshRate = 90.0f;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.desiredRefreshRate = 60.0f;
+ lr2.vote = LayerVoteType::Max;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.desiredRefreshRate = 30.0f;
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.desiredRefreshRate = 90.0f;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.desiredRefreshRate = 30.0f;
+ lr2.vote = LayerVoteType::Max;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+}
+
} // namespace
} // namespace scheduler
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
index cffdc14..18b1063 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
@@ -27,7 +27,7 @@
#include "BufferQueueLayer.h"
#include "BufferStateLayer.h"
-#include "ColorLayer.h"
+#include "EffectLayer.h"
#include "Layer.h"
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
@@ -68,7 +68,7 @@
void setupComposer(int virtualDisplayCount);
sp<BufferQueueLayer> createBufferQueueLayer();
sp<BufferStateLayer> createBufferStateLayer();
- sp<ColorLayer> createColorLayer();
+ sp<EffectLayer> createEffectLayer();
void setParent(Layer* child, Layer* parent);
void commitTransaction(Layer* layer);
@@ -111,11 +111,11 @@
return new BufferStateLayer(args);
}
-sp<ColorLayer> RefreshRateSelectionTest::createColorLayer() {
+sp<EffectLayer> RefreshRateSelectionTest::createEffectLayer() {
sp<Client> client;
LayerCreationArgs args(mFlinger.flinger(), client, "color-layer", WIDTH, HEIGHT, LAYER_FLAGS,
LayerMetadata());
- return new ColorLayer(args);
+ return new EffectLayer(args);
}
void RefreshRateSelectionTest::setParent(Layer* child, Layer* parent) {
@@ -153,8 +153,6 @@
void RefreshRateSelectionTest::setupComposer(int virtualDisplayCount) {
mComposer = new Hwc2::mock::Composer();
- EXPECT_CALL(*mComposer, getCapabilities())
- .WillOnce(Return(std::vector<IComposer::Capability>()));
EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
@@ -244,11 +242,11 @@
ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
}
-TEST_F(RefreshRateSelectionTest, testPriorityOnColorLayers) {
- mParent = createColorLayer();
- mChild = createColorLayer();
+TEST_F(RefreshRateSelectionTest, testPriorityOnEffectLayers) {
+ mParent = createEffectLayer();
+ mChild = createEffectLayer();
setParent(mChild.get(), mParent.get());
- mGrandChild = createColorLayer();
+ mGrandChild = createEffectLayer();
setParent(mGrandChild.get(), mChild.get());
ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 89002a8..5db11ec 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -159,6 +159,11 @@
EXPECT_CALL(*mEventThread, setPhaseOffset(10)).Times(1);
ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(mConnectionHandle, 10));
+
+ static constexpr size_t kEventConnections = 5;
+ ON_CALL(*mEventThread, getEventThreadConnectionCount())
+ .WillByDefault(Return(kEventConnections));
+ EXPECT_EQ(kEventConnections, mScheduler->getEventThreadConnectionCount(mConnectionHandle));
}
} // namespace
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 798ba76..3a4f349 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -25,9 +25,9 @@
#include "BufferQueueLayer.h"
#include "BufferStateLayer.h"
-#include "ColorLayer.h"
#include "ContainerLayer.h"
#include "DisplayDevice.h"
+#include "EffectLayer.h"
#include "FakePhaseOffsets.h"
#include "Layer.h"
#include "NativeWindowSurface.h"
@@ -147,9 +147,7 @@
return nullptr;
}
- sp<ColorLayer> createColorLayer(const LayerCreationArgs&) override {
- return nullptr;
- }
+ sp<EffectLayer> createEffectLayer(const LayerCreationArgs&) override { return nullptr; }
sp<ContainerLayer> createContainerLayer(const LayerCreationArgs&) override {
return nullptr;
@@ -545,10 +543,11 @@
class FakeDisplayDeviceInjector {
public:
FakeDisplayDeviceInjector(TestableSurfaceFlinger& flinger,
- const std::optional<DisplayId>& displayId, bool isVirtual,
+ std::optional<DisplayId> displayId,
+ std::optional<DisplayConnectionType> connectionType,
bool isPrimary)
: mFlinger(flinger), mCreationArgs(flinger.mFlinger.get(), mDisplayToken, displayId) {
- mCreationArgs.isVirtual = isVirtual;
+ mCreationArgs.connectionType = connectionType;
mCreationArgs.isPrimary = isPrimary;
}
@@ -611,7 +610,12 @@
sp<DisplayDevice> inject() {
DisplayDeviceState state;
- state.displayId = mCreationArgs.isVirtual ? std::nullopt : mCreationArgs.displayId;
+ if (const auto type = mCreationArgs.connectionType) {
+ const auto id = mCreationArgs.displayId;
+ LOG_ALWAYS_FATAL_IF(!id);
+ state.physical = {*id, *type};
+ }
+
state.isSecure = mCreationArgs.isSecure;
sp<DisplayDevice> device = new DisplayDevice(std::move(mCreationArgs));
@@ -619,9 +623,8 @@
mFlinger.mutableCurrentState().displays.add(mDisplayToken, state);
mFlinger.mutableDrawingState().displays.add(mDisplayToken, state);
- if (!mCreationArgs.isVirtual) {
- LOG_ALWAYS_FATAL_IF(!state.displayId);
- mFlinger.mutablePhysicalDisplayTokens()[*state.displayId] = mDisplayToken;
+ if (const auto& physical = state.physical) {
+ mFlinger.mutablePhysicalDisplayTokens()[physical->id] = mDisplayToken;
}
return device;
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index fb2e3bd..a7a4d48 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -166,6 +166,7 @@
MOCK_METHOD1(unregisterStatsPullAtomCallback, void(int32_t));
MOCK_METHOD2(statsEventSetAtomId, void(AStatsEvent*, uint32_t));
+ MOCK_METHOD2(statsEventWriteInt32, void(AStatsEvent*, int32_t));
MOCK_METHOD2(statsEventWriteInt64, void(AStatsEvent*, int64_t));
MOCK_METHOD2(statsEventWriteString8, void(AStatsEvent*, const char*));
MOCK_METHOD3(statsEventWriteByteArray, void(AStatsEvent*, const uint8_t*, size_t));
@@ -796,59 +797,6 @@
ASSERT_EQ(0, globalProto.stats_size());
}
-TEST_F(TimeStatsTest, globalStatsCallback) {
- constexpr size_t TOTAL_FRAMES = 5;
- constexpr size_t MISSED_FRAMES = 4;
- constexpr size_t CLIENT_COMPOSITION_FRAMES = 3;
-
- mTimeStats->onBootFinished();
- EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
-
- for (size_t i = 0; i < TOTAL_FRAMES; i++) {
- mTimeStats->incrementTotalFrames();
- }
- for (size_t i = 0; i < MISSED_FRAMES; i++) {
- mTimeStats->incrementMissedFrames();
- }
- for (size_t i = 0; i < CLIENT_COMPOSITION_FRAMES; i++) {
- mTimeStats->incrementClientCompositionFrames();
- }
-
- mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
- mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
- mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
-
- EXPECT_THAT(mDelegate->mAtomTags,
- UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
- android::util::SURFACEFLINGER_STATS_LAYER_INFO));
- EXPECT_NE(nullptr, mDelegate->mCallback);
- EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
-
- {
- InSequence seq;
- EXPECT_CALL(*mDelegate,
- statsEventSetAtomId(mDelegate->mEvent,
- android::util::SURFACEFLINGER_STATS_GLOBAL_INFO));
- EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, TOTAL_FRAMES));
- EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, MISSED_FRAMES));
- EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, CLIENT_COMPOSITION_FRAMES));
- EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, _));
- EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 2));
- EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
- }
- EXPECT_EQ(AStatsManager_PULL_SUCCESS,
- mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
- mDelegate->mCookie));
-
- SFTimeStatsGlobalProto globalProto;
- ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
-
- EXPECT_EQ(0, globalProto.total_frames());
- EXPECT_EQ(0, globalProto.missed_frames());
- EXPECT_EQ(0, globalProto.client_composition_frames());
- EXPECT_EQ(0, globalProto.present_to_present_size());
-}
-
namespace {
std::string buildExpectedHistogramBytestring(const std::vector<int32_t>& times,
const std::vector<int32_t>& frameCounts) {
@@ -892,6 +840,80 @@
return expected == actual;
}
+TEST_F(TimeStatsTest, globalStatsCallback) {
+ constexpr size_t TOTAL_FRAMES = 5;
+ constexpr size_t MISSED_FRAMES = 4;
+ constexpr size_t CLIENT_COMPOSITION_FRAMES = 3;
+ constexpr size_t DISPLAY_EVENT_CONNECTIONS = 14;
+
+ mTimeStats->onBootFinished();
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+ for (size_t i = 0; i < TOTAL_FRAMES; i++) {
+ mTimeStats->incrementTotalFrames();
+ }
+ for (size_t i = 0; i < MISSED_FRAMES; i++) {
+ mTimeStats->incrementMissedFrames();
+ }
+ for (size_t i = 0; i < CLIENT_COMPOSITION_FRAMES; i++) {
+ mTimeStats->incrementClientCompositionFrames();
+ }
+
+ mTimeStats->recordDisplayEventConnectionCount(DISPLAY_EVENT_CONNECTIONS);
+ mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+ mTimeStats->recordFrameDuration(1000000, 3000000);
+ mTimeStats->recordRenderEngineDuration(2000000, 4000000);
+ mTimeStats->recordRenderEngineDuration(2000000, std::make_shared<FenceTime>(3000000));
+
+ mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
+ mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
+
+ EXPECT_THAT(mDelegate->mAtomTags,
+ UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+ EXPECT_NE(nullptr, mDelegate->mCallback);
+ EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
+
+ std::string expectedFrameDuration = buildExpectedHistogramBytestring({2}, {1});
+ std::string expectedRenderEngineTiming = buildExpectedHistogramBytestring({1, 2}, {1, 1});
+
+ {
+ InSequence seq;
+ EXPECT_CALL(*mDelegate,
+ statsEventSetAtomId(mDelegate->mEvent,
+ android::util::SURFACEFLINGER_STATS_GLOBAL_INFO));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, TOTAL_FRAMES));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, MISSED_FRAMES));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, CLIENT_COMPOSITION_FRAMES));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, _));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 2));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, DISPLAY_EVENT_CONNECTIONS));
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteByteArray(mDelegate->mEvent,
+ BytesEq((const uint8_t*)expectedFrameDuration.c_str(),
+ expectedFrameDuration.size()),
+ expectedFrameDuration.size()));
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteByteArray(mDelegate->mEvent,
+ BytesEq((const uint8_t*)
+ expectedRenderEngineTiming.c_str(),
+ expectedRenderEngineTiming.size()),
+ expectedRenderEngineTiming.size()));
+ EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
+ }
+ EXPECT_EQ(AStatsManager_PULL_SUCCESS,
+ mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ mDelegate->mCookie));
+
+ SFTimeStatsGlobalProto globalProto;
+ ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
+
+ EXPECT_EQ(0, globalProto.total_frames());
+ EXPECT_EQ(0, globalProto.missed_frames());
+ EXPECT_EQ(0, globalProto.client_composition_frames());
+ EXPECT_EQ(0, globalProto.present_to_present_size());
+}
+
TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) {
constexpr size_t LATE_ACQUIRE_FRAMES = 2;
constexpr size_t BAD_DESIRED_PRESENT_FRAMES = 3;
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
index 6ec3844..f834af8 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -36,7 +36,7 @@
namespace android::scheduler {
MATCHER_P2(IsCloseTo, value, tolerance, "is within tolerance") {
- return arg <= value + tolerance && value >= value - tolerance;
+ return arg <= value + tolerance && arg >= value - tolerance;
}
std::vector<nsecs_t> generateVsyncTimestamps(size_t count, nsecs_t period, nsecs_t bias) {
@@ -370,6 +370,26 @@
IsCloseTo(idealPeriod, mMaxRoundingError));
}
+TEST_F(VSyncPredictorTest, slopeAlwaysValid) {
+ constexpr auto kNumVsyncs = 100;
+ auto invalidPeriod = mPeriod;
+ auto now = 0;
+ for (int i = 0; i < kNumVsyncs; i++) {
+ tracker.addVsyncTimestamp(now);
+ now += invalidPeriod;
+ invalidPeriod *= 0.9f;
+
+ auto [slope, intercept] = tracker.getVSyncPredictionModel();
+ EXPECT_THAT(slope, IsCloseTo(mPeriod, mPeriod * kOutlierTolerancePercent / 100.f));
+
+ // When VsyncPredictor returns the period it means that it doesn't know how to predict and
+ // it needs to get more samples
+ if (slope == mPeriod && intercept == 0) {
+ EXPECT_TRUE(tracker.needsMoreSamples(now));
+ }
+ }
+}
+
} // namespace android::scheduler
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
index 2f36bb2..ac95938 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -534,6 +534,30 @@
mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
}
+// b/149221293
+TEST_F(VSyncReactorTest, selfRemovingEventListenerStopsCallbacks) {
+ class SelfRemovingCallback : public DispSync::Callback {
+ public:
+ SelfRemovingCallback(VSyncReactor& vsr) : mVsr(vsr) {}
+ void onDispSyncEvent(nsecs_t when) final { mVsr.removeEventListener(this, &when); }
+
+ private:
+ VSyncReactor& mVsr;
+ } selfRemover(mReactor);
+
+ Sequence seq;
+ EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
+ .InSequence(seq)
+ .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken)));
+ EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
+ .InSequence(seq);
+ EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).Times(2).InSequence(seq);
+ EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq);
+
+ mReactor.addEventListener(mName, mPhase, &selfRemover, lastCallbackTime);
+ innerCb(0, 0);
+}
+
TEST_F(VSyncReactorTest, addEventListenerChangePeriod) {
Sequence seq;
EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index 9bda095..50eb390 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -42,6 +42,7 @@
MOCK_METHOD1(requestNextVsync, void(const sp<android::EventThreadConnection> &));
MOCK_METHOD0(requestLatestConfig, void());
MOCK_METHOD1(pauseVsyncCallback, void(bool));
+ MOCK_METHOD0(getEventThreadConnectionCount, size_t());
};
} // namespace mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
index 2720537..c45d584 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -36,6 +36,7 @@
MOCK_METHOD0(incrementMissedFrames, void());
MOCK_METHOD0(incrementClientCompositionFrames, void());
MOCK_METHOD0(incrementClientCompositionReusedFrames, void());
+ MOCK_METHOD1(recordDisplayEventConnectionCount, void(int32_t));
MOCK_METHOD2(recordFrameDuration, void(nsecs_t, nsecs_t));
MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, nsecs_t));
MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, const std::shared_ptr<FenceTime>&));