Merge "Add AHARDWAREBUFFER_FORMAT_YCBCR_P010"
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 8ccd940..1003aae 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1582,7 +1582,6 @@
DumpFile("BUDDYINFO", "/proc/buddyinfo");
DumpExternalFragmentationInfo();
- DumpFile("KERNEL WAKE SOURCES", "/d/wakeup_sources");
DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
RunCommand("PROCESSES AND THREADS",
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 00babc3..fd38ddf 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -10,6 +10,7 @@
cc_defaults {
name: "installd_defaults",
+ cpp_std: "c++2a",
cflags: [
"-Wall",
"-Werror",
@@ -41,6 +42,7 @@
"libbinder",
"libcrypto",
"libcutils",
+ "libext2_uuid",
"liblog",
"liblogwrap",
"libprocessgroup",
@@ -239,6 +241,8 @@
cc_binary {
name: "otapreopt",
+
+ cpp_std: "c++2a",
cflags: [
"-Wall",
"-Werror",
@@ -268,6 +272,7 @@
"libbase",
"libcrypto",
"libcutils",
+ "libext2_uuid",
"liblog",
"liblogwrap",
"libprocessgroup",
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 2207405..f0dcd02 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -103,11 +103,6 @@
static constexpr const char* CACHE_DIR_POSTFIX = "/cache";
static constexpr const char* CODE_CACHE_DIR_POSTFIX = "/code_cache";
-// fsverity assumes the page size is always 4096. If not, the feature can not be
-// enabled.
-static constexpr int kVerityPageSize = 4096;
-static constexpr size_t kSha256Size = 32;
-static constexpr const char* kPropApkVerityMode = "ro.apk_verity.mode";
static constexpr const char* kFuseProp = "persist.sys.fuse";
/**
@@ -261,12 +256,6 @@
} \
}
-#define ASSERT_PAGE_SIZE_4K() { \
- if (getpagesize() != kVerityPageSize) { \
- return error("FSVerity only supports 4K pages"); \
- } \
-}
-
#ifdef GRANULAR_LOCKS
/**
@@ -698,9 +687,6 @@
if (!status.isOk()) {
return status;
}
- if (previousUid != uid) {
- chown_app_profile_dir(packageName, appId, userId);
- }
// Remember inode numbers of cache directories so that we can clear
// contents while CE storage is locked
@@ -726,6 +712,9 @@
if (!status.isOk()) {
return status;
}
+ if (previousUid != uid) {
+ chown_app_profile_dir(packageName, appId, userId);
+ }
if (!prepare_app_profile_dir(packageName, appId, userId)) {
return error("Failed to prepare profiles for " + packageName);
@@ -968,13 +957,13 @@
binder::Status res = ok();
if (flags & FLAG_STORAGE_CE) {
auto path = create_data_user_ce_package_path(uuid_, userId, pkgname, ceDataInode);
- if (delete_dir_contents_and_dir(path) != 0) {
+ if (rename_delete_dir_contents_and_dir(path) != 0) {
res = error("Failed to delete " + path);
}
}
if (flags & FLAG_STORAGE_DE) {
auto path = create_data_user_de_package_path(uuid_, userId, pkgname);
- if (delete_dir_contents_and_dir(path) != 0) {
+ if (rename_delete_dir_contents_and_dir(path) != 0) {
res = error("Failed to delete " + path);
}
if ((flags & FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES) == 0) {
@@ -1005,16 +994,15 @@
}
auto path = StringPrintf("%s/Android/data/%s", extPath.c_str(), pkgname);
- if (delete_dir_contents_and_dir(path, true) != 0) {
+ if (rename_delete_dir_contents_and_dir(path, true) != 0) {
res = error("Failed to delete contents of " + path);
}
-
path = StringPrintf("%s/Android/media/%s", extPath.c_str(), pkgname);
- if (delete_dir_contents_and_dir(path, true) != 0) {
+ if (rename_delete_dir_contents_and_dir(path, true) != 0) {
res = error("Failed to delete contents of " + path);
}
path = StringPrintf("%s/Android/obb/%s", extPath.c_str(), pkgname);
- if (delete_dir_contents_and_dir(path, true) != 0) {
+ if (rename_delete_dir_contents_and_dir(path, true) != 0) {
res = error("Failed to delete contents of " + path);
}
}
@@ -1562,27 +1550,27 @@
binder::Status res = ok();
if (flags & FLAG_STORAGE_DE) {
auto path = create_data_user_de_path(uuid_, userId);
- if (delete_dir_contents_and_dir(path, true) != 0) {
+ if (rename_delete_dir_contents_and_dir(path, true) != 0) {
res = error("Failed to delete " + path);
}
if (uuid_ == nullptr) {
path = create_data_misc_legacy_path(userId);
- if (delete_dir_contents_and_dir(path, true) != 0) {
+ if (rename_delete_dir_contents_and_dir(path, true) != 0) {
res = error("Failed to delete " + path);
}
path = create_primary_cur_profile_dir_path(userId);
- if (delete_dir_contents_and_dir(path, true) != 0) {
+ if (rename_delete_dir_contents_and_dir(path, true) != 0) {
res = error("Failed to delete " + path);
}
}
}
if (flags & FLAG_STORAGE_CE) {
auto path = create_data_user_ce_path(uuid_, userId);
- if (delete_dir_contents_and_dir(path, true) != 0) {
+ if (rename_delete_dir_contents_and_dir(path, true) != 0) {
res = error("Failed to delete " + path);
}
path = findDataMediaPath(uuid, userId);
- if (delete_dir_contents_and_dir(path, true) != 0) {
+ if (rename_delete_dir_contents_and_dir(path, true) != 0) {
res = error("Failed to delete " + path);
}
}
@@ -2972,147 +2960,6 @@
return *_aidl_return == -1 ? error() : ok();
}
-// This kernel feature is experimental.
-// TODO: remove local definition once upstreamed
-#ifndef FS_IOC_ENABLE_VERITY
-
-#define FS_IOC_ENABLE_VERITY _IO('f', 133)
-#define FS_IOC_SET_VERITY_MEASUREMENT _IOW('f', 134, struct fsverity_measurement)
-
-#define FS_VERITY_ALG_SHA256 1
-
-struct fsverity_measurement {
- __u16 digest_algorithm;
- __u16 digest_size;
- __u32 reserved1;
- __u64 reserved2[3];
- __u8 digest[];
-};
-
-#endif
-
-binder::Status InstalldNativeService::installApkVerity(const std::string& packageName,
- const std::string& filePath,
- android::base::unique_fd verityInputAshmem,
- int32_t contentSize) {
- ENFORCE_UID(AID_SYSTEM);
- CHECK_ARGUMENT_PACKAGE_NAME(packageName);
- CHECK_ARGUMENT_PATH(filePath);
- LOCK_PACKAGE();
-
- if (!android::base::GetBoolProperty(kPropApkVerityMode, false)) {
- return ok();
- }
-#ifndef NDEBUG
- ASSERT_PAGE_SIZE_4K();
-#endif
- // TODO: also check fsverity support in the current file system if compiled with DEBUG.
- // TODO: change ashmem to some temporary file to support huge apk.
- if (!ashmem_valid(verityInputAshmem.get())) {
- return error("FD is not an ashmem");
- }
-
- // 1. Seek to the next page boundary beyond the end of the file.
- ::android::base::unique_fd wfd(open(filePath.c_str(), O_WRONLY));
- if (wfd.get() < 0) {
- return error("Failed to open " + filePath);
- }
- struct stat st;
- if (fstat(wfd.get(), &st) < 0) {
- return error("Failed to stat " + filePath);
- }
- // fsverity starts from the block boundary.
- off_t padding = kVerityPageSize - st.st_size % kVerityPageSize;
- if (padding == kVerityPageSize) {
- padding = 0;
- }
- if (lseek(wfd.get(), st.st_size + padding, SEEK_SET) < 0) {
- return error("Failed to lseek " + filePath);
- }
-
- // 2. Write everything in the ashmem to the file. Note that allocated
- // ashmem size is multiple of page size, which is different from the
- // actual content size.
- int shmSize = ashmem_get_size_region(verityInputAshmem.get());
- if (shmSize < 0) {
- return error("Failed to get ashmem size: " + std::to_string(shmSize));
- }
- if (contentSize < 0) {
- return error("Invalid content size: " + std::to_string(contentSize));
- }
- if (contentSize > shmSize) {
- return error("Content size overflow: " + std::to_string(contentSize) + " > " +
- std::to_string(shmSize));
- }
- auto data = std::unique_ptr<void, std::function<void (void *)>>(
- mmap(nullptr, contentSize, PROT_READ, MAP_SHARED, verityInputAshmem.get(), 0),
- [contentSize] (void* ptr) {
- if (ptr != MAP_FAILED) {
- munmap(ptr, contentSize);
- }
- });
-
- if (data.get() == MAP_FAILED) {
- return error("Failed to mmap the ashmem");
- }
- char* cursor = reinterpret_cast<char*>(data.get());
- int remaining = contentSize;
- while (remaining > 0) {
- int ret = TEMP_FAILURE_RETRY(write(wfd.get(), cursor, remaining));
- if (ret < 0) {
- return error("Failed to write to " + filePath + " (" + std::to_string(remaining) +
- + "/" + std::to_string(contentSize) + ")");
- }
- cursor += ret;
- remaining -= ret;
- }
- wfd.reset();
-
- // 3. Enable fsverity (needs readonly fd. Once it's done, the file becomes immutable.
- ::android::base::unique_fd rfd(open(filePath.c_str(), O_RDONLY));
- if (ioctl(rfd.get(), FS_IOC_ENABLE_VERITY, nullptr) < 0) {
- return error("Failed to enable fsverity on " + filePath);
- }
- return ok();
-}
-
-binder::Status InstalldNativeService::assertFsverityRootHashMatches(
- const std::string& packageName, const std::string& filePath,
- const std::vector<uint8_t>& expectedHash) {
- ENFORCE_UID(AID_SYSTEM);
- CHECK_ARGUMENT_PACKAGE_NAME(packageName);
- CHECK_ARGUMENT_PATH(filePath);
- LOCK_PACKAGE();
-
- if (!android::base::GetBoolProperty(kPropApkVerityMode, false)) {
- return ok();
- }
- // TODO: also check fsverity support in the current file system if compiled with DEBUG.
- if (expectedHash.size() != kSha256Size) {
- return error("verity hash size should be " + std::to_string(kSha256Size) + " but is " +
- std::to_string(expectedHash.size()));
- }
-
- ::android::base::unique_fd fd(open(filePath.c_str(), O_RDONLY));
- if (fd.get() < 0) {
- return error("Failed to open " + filePath + ": " + strerror(errno));
- }
-
- unsigned int buffer_size = sizeof(fsverity_measurement) + kSha256Size;
- std::vector<char> buffer(buffer_size, 0);
-
- fsverity_measurement* config = reinterpret_cast<fsverity_measurement*>(buffer.data());
- config->digest_algorithm = FS_VERITY_ALG_SHA256;
- config->digest_size = kSha256Size;
- memcpy(config->digest, expectedHash.data(), kSha256Size);
- if (ioctl(fd.get(), FS_IOC_SET_VERITY_MEASUREMENT, config) < 0) {
- // This includes an expected failure case with no FSVerity setup. It normally happens when
- // the apk does not contains the Merkle tree root hash.
- return error("Failed to measure fsverity on " + filePath + ": " + strerror(errno));
- }
- return ok(); // hashes match
-}
-
binder::Status InstalldNativeService::reconcileSecondaryDexFile(
const std::string& dexPath, const std::string& packageName, int32_t uid,
const std::vector<std::string>& isas, const std::optional<std::string>& volumeUuid,
@@ -3342,5 +3189,22 @@
return ok();
}
+binder::Status InstalldNativeService::cleanupInvalidPackageDirs(
+ const std::optional<std::string>& uuid, int32_t userId, int32_t flags) {
+ const char* uuid_cstr = uuid ? uuid->c_str() : nullptr;
+
+ if (flags & FLAG_STORAGE_CE) {
+ auto ce_path = create_data_user_ce_path(uuid_cstr, userId);
+ cleanup_invalid_package_dirs_under_path(ce_path);
+ }
+
+ if (flags & FLAG_STORAGE_DE) {
+ auto de_path = create_data_user_de_path(uuid_cstr, userId);
+ cleanup_invalid_package_dirs_under_path(de_path);
+ }
+
+ return ok();
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 04662ea..ecc60b5 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -165,11 +165,6 @@
binder::Status deleteOdex(const std::string& packageName, const std::string& apkPath,
const std::string& instructionSet,
const std::optional<std::string>& outputPath, int64_t* _aidl_return);
- binder::Status installApkVerity(const std::string& packageName, const std::string& filePath,
- android::base::unique_fd verityInput, int32_t contentSize);
- binder::Status assertFsverityRootHashMatches(const std::string& packageName,
- const std::string& filePath,
- const std::vector<uint8_t>& expectedHash);
binder::Status reconcileSecondaryDexFile(const std::string& dexPath,
const std::string& packageName, int32_t uid, const std::vector<std::string>& isa,
const std::optional<std::string>& volumeUuid, int32_t storage_flag, bool* _aidl_return);
@@ -190,6 +185,9 @@
binder::Status migrateLegacyObbData();
+ binder::Status cleanupInvalidPackageDirs(const std::optional<std::string>& uuid, int32_t userId,
+ int32_t flags);
+
private:
std::recursive_mutex mLock;
std::unordered_map<userid_t, std::weak_ptr<std::shared_mutex>> mUserIdLock;
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 684a311..afedcc6 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -97,10 +97,6 @@
@utf8InCpp String instructionSet, @utf8InCpp String outputPath);
long deleteOdex(@utf8InCpp String packageName, @utf8InCpp String apkPath,
@utf8InCpp String instructionSet, @nullable @utf8InCpp String outputPath);
- void installApkVerity(@utf8InCpp String packageName, @utf8InCpp String filePath,
- in FileDescriptor verityInput, int contentSize);
- void assertFsverityRootHashMatches(@utf8InCpp String packageName, @utf8InCpp String filePath,
- in byte[] expectedHash);
boolean reconcileSecondaryDexFile(@utf8InCpp String dexPath, @utf8InCpp String pkgName,
int uid, in @utf8InCpp String[] isas, @nullable @utf8InCpp String volume_uuid,
@@ -130,6 +126,8 @@
void migrateLegacyObbData();
+ void cleanupInvalidPackageDirs(@nullable @utf8InCpp String uuid, int userId, int flags);
+
const int FLAG_STORAGE_DE = 0x1;
const int FLAG_STORAGE_CE = 0x2;
const int FLAG_STORAGE_EXTERNAL = 0x4;
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index 51f7716..a16587e 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -8,46 +8,47 @@
default_applicable_licenses: ["frameworks_native_license"],
}
-cc_test {
- name: "installd_utils_test",
+cc_defaults {
+ name: "installd_tests_defaults",
test_suites: ["device-tests"],
clang: true,
- srcs: ["installd_utils_test.cpp"],
+ cpp_std: "c++2a",
cflags: [
"-Wall",
"-Werror",
],
shared_libs: [
"libbase",
- "libutils",
"libcutils",
+ "libext2_uuid",
+ "libutils",
],
static_libs: [
+ "liblog",
+ ],
+}
+
+cc_test {
+ name: "installd_utils_test",
+ defaults: ["installd_tests_defaults"],
+ srcs: ["installd_utils_test.cpp"],
+ static_libs: [
"libasync_safe",
"libdiskusage",
"libinstalld",
- "liblog",
],
test_config: "installd_utils_test.xml",
}
cc_test {
name: "installd_cache_test",
- test_suites: ["device-tests"],
- clang: true,
+ defaults: ["installd_tests_defaults"],
srcs: ["installd_cache_test.cpp"],
- cflags: [
- "-Wall",
- "-Werror",
- ],
shared_libs: [
- "libbase",
"libbinder",
"libcrypto",
- "libcutils",
"libprocessgroup",
"libselinux",
- "libutils",
"server_configurable_flags",
],
static_libs: [
@@ -55,7 +56,6 @@
"libdiskusage",
"libinstalld",
"libziparchive",
- "liblog",
"liblogwrap",
],
test_config: "installd_cache_test.xml",
@@ -78,21 +78,13 @@
cc_test {
name: "installd_service_test",
- test_suites: ["device-tests"],
- clang: true,
+ defaults: ["installd_tests_defaults"],
srcs: ["installd_service_test.cpp"],
- cflags: [
- "-Wall",
- "-Werror",
- ],
shared_libs: [
- "libbase",
"libbinder",
"libcrypto",
- "libcutils",
"libprocessgroup",
"libselinux",
- "libutils",
"packagemanager_aidl-cpp",
"server_configurable_flags",
],
@@ -101,7 +93,6 @@
"libdiskusage",
"libinstalld",
"libziparchive",
- "liblog",
"liblogwrap",
],
test_config: "installd_service_test.xml",
@@ -124,28 +115,19 @@
cc_test {
name: "installd_dexopt_test",
- test_suites: ["device-tests"],
- clang: true,
+ defaults: ["installd_tests_defaults"],
srcs: ["installd_dexopt_test.cpp"],
- cflags: [
- "-Wall",
- "-Werror",
- ],
shared_libs: [
- "libbase",
"libbinder",
"libcrypto",
- "libcutils",
"libprocessgroup",
"libselinux",
- "libutils",
"server_configurable_flags",
],
static_libs: [
"libasync_safe",
"libdiskusage",
"libinstalld",
- "liblog",
"liblogwrap",
"libziparchive",
"libz",
@@ -170,41 +152,21 @@
cc_test {
name: "installd_otapreopt_test",
- test_suites: ["device-tests"],
- clang: true,
+ defaults: ["installd_tests_defaults"],
srcs: ["installd_otapreopt_test.cpp"],
- cflags: [
- "-Wall",
- "-Werror",
- ],
shared_libs: [
- "libbase",
- "libcutils",
- "libutils",
"server_configurable_flags",
],
static_libs: [
- "liblog",
"libotapreoptparameters",
],
}
cc_test {
name: "installd_file_test",
- test_suites: ["device-tests"],
- clang: true,
+ defaults: ["installd_tests_defaults"],
srcs: ["installd_file_test.cpp"],
- cflags: [
- "-Wall",
- "-Werror",
- ],
- shared_libs: [
- "libbase",
- "libcutils",
- "libutils",
- ],
static_libs: [
"libinstalld",
- "liblog",
],
}
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index b831515..806797f 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -75,6 +75,7 @@
namespace installd {
constexpr const char* kTestUuid = "TEST";
+constexpr const char* kTestPath = "/data/local/tmp/user/0";
#define FLAG_FORCE InstalldNativeService::FLAG_FORCE
@@ -97,7 +98,7 @@
}
static std::string get_full_path(const char* path) {
- return StringPrintf("/data/local/tmp/user/0/%s", path);
+ return StringPrintf("%s/%s", kTestPath, path);
}
static void mkdir(const char* path, uid_t owner, gid_t group, mode_t mode) {
@@ -107,12 +108,16 @@
EXPECT_EQ(::chmod(fullPath.c_str(), mode), 0);
}
-static void touch(const char* path, uid_t owner, gid_t group, mode_t mode) {
+static int create(const char* path, uid_t owner, gid_t group, mode_t mode) {
int fd = ::open(get_full_path(path).c_str(), O_RDWR | O_CREAT, mode);
EXPECT_NE(fd, -1);
EXPECT_EQ(::fchown(fd, owner, group), 0);
EXPECT_EQ(::fchmod(fd, mode), 0);
- EXPECT_EQ(::close(fd), 0);
+ return fd;
+}
+
+static void touch(const char* path, uid_t owner, gid_t group, mode_t mode) {
+ EXPECT_EQ(::close(create(path, owner, group, mode)), 0);
}
static int stat_gid(const char* path) {
@@ -127,6 +132,35 @@
return buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISGID);
}
+static bool exists(const char* path) {
+ return ::access(get_full_path(path).c_str(), F_OK) == 0;
+}
+
+template <class Pred>
+static bool find_file(const char* path, Pred&& pred) {
+ bool result = false;
+ auto d = opendir(path);
+ if (d == nullptr) {
+ return result;
+ }
+ struct dirent* de;
+ while ((de = readdir(d))) {
+ const char* name = de->d_name;
+ if (pred(name, de->d_type == DT_DIR)) {
+ result = true;
+ break;
+ }
+ }
+ closedir(d);
+ return result;
+}
+
+static bool exists_renamed_deleted_dir() {
+ return find_file(kTestPath, [](std::string_view name, bool is_dir) {
+ return is_dir && is_renamed_deleted_dir(name);
+ });
+}
+
class ServiceTest : public testing::Test {
protected:
InstalldNativeService* service;
@@ -193,6 +227,134 @@
EXPECT_EQ(10000, stat_gid("com.example/bar/file"));
}
+TEST_F(ServiceTest, DestroyUserData) {
+ LOG(INFO) << "DestroyUserData";
+
+ mkdir("com.example", 10000, 10000, 0700);
+ mkdir("com.example/foo", 10000, 10000, 0700);
+ touch("com.example/foo/file", 10000, 20000, 0700);
+ mkdir("com.example/bar", 10000, 20000, 0700);
+ touch("com.example/bar/file", 10000, 20000, 0700);
+
+ EXPECT_TRUE(exists("com.example/foo"));
+ EXPECT_TRUE(exists("com.example/foo/file"));
+ EXPECT_TRUE(exists("com.example/bar"));
+ EXPECT_TRUE(exists("com.example/bar/file"));
+
+ service->destroyUserData(testUuid, 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE);
+
+ EXPECT_FALSE(exists("com.example/foo"));
+ EXPECT_FALSE(exists("com.example/foo/file"));
+ EXPECT_FALSE(exists("com.example/bar"));
+ EXPECT_FALSE(exists("com.example/bar/file"));
+
+ EXPECT_FALSE(exists_renamed_deleted_dir());
+}
+
+TEST_F(ServiceTest, DestroyAppData) {
+ LOG(INFO) << "DestroyAppData";
+
+ mkdir("com.example", 10000, 10000, 0700);
+ mkdir("com.example/foo", 10000, 10000, 0700);
+ touch("com.example/foo/file", 10000, 20000, 0700);
+ mkdir("com.example/bar", 10000, 20000, 0700);
+ touch("com.example/bar/file", 10000, 20000, 0700);
+
+ EXPECT_TRUE(exists("com.example/foo"));
+ EXPECT_TRUE(exists("com.example/foo/file"));
+ EXPECT_TRUE(exists("com.example/bar"));
+ EXPECT_TRUE(exists("com.example/bar/file"));
+
+ service->destroyAppData(testUuid, "com.example", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE, 0);
+
+ EXPECT_FALSE(exists("com.example/foo"));
+ EXPECT_FALSE(exists("com.example/foo/file"));
+ EXPECT_FALSE(exists("com.example/bar"));
+ EXPECT_FALSE(exists("com.example/bar/file"));
+
+ EXPECT_FALSE(exists_renamed_deleted_dir());
+}
+
+TEST_F(ServiceTest, CleanupInvalidPackageDirs) {
+ LOG(INFO) << "CleanupInvalidPackageDirs";
+
+ mkdir("5b14b6458a44==deleted==", 10000, 10000, 0700);
+ mkdir("5b14b6458a44==deleted==/foo", 10000, 10000, 0700);
+ touch("5b14b6458a44==deleted==/foo/file", 10000, 20000, 0700);
+ mkdir("5b14b6458a44==deleted==/bar", 10000, 20000, 0700);
+ touch("5b14b6458a44==deleted==/bar/file", 10000, 20000, 0700);
+
+ auto fd = create("5b14b6458a44==deleted==/bar/opened_file", 10000, 20000, 0700);
+
+ mkdir("b14b6458a44NOTdeleted", 10000, 10000, 0700);
+ mkdir("b14b6458a44NOTdeleted/foo", 10000, 10000, 0700);
+ touch("b14b6458a44NOTdeleted/foo/file", 10000, 20000, 0700);
+ mkdir("b14b6458a44NOTdeleted/bar", 10000, 20000, 0700);
+ touch("b14b6458a44NOTdeleted/bar/file", 10000, 20000, 0700);
+
+ mkdir("com.example", 10000, 10000, 0700);
+ mkdir("com.example/foo", 10000, 10000, 0700);
+ touch("com.example/foo/file", 10000, 20000, 0700);
+ mkdir("com.example/bar", 10000, 20000, 0700);
+ touch("com.example/bar/file", 10000, 20000, 0700);
+
+ mkdir("==deleted==", 10000, 10000, 0700);
+ mkdir("==deleted==/foo", 10000, 10000, 0700);
+ touch("==deleted==/foo/file", 10000, 20000, 0700);
+ mkdir("==deleted==/bar", 10000, 20000, 0700);
+ touch("==deleted==/bar/file", 10000, 20000, 0700);
+
+ EXPECT_TRUE(exists("5b14b6458a44==deleted==/foo"));
+ EXPECT_TRUE(exists("5b14b6458a44==deleted==/foo/file"));
+ EXPECT_TRUE(exists("5b14b6458a44==deleted==/bar"));
+ EXPECT_TRUE(exists("5b14b6458a44==deleted==/bar/file"));
+ EXPECT_TRUE(exists("5b14b6458a44==deleted==/bar/opened_file"));
+
+ EXPECT_TRUE(exists("b14b6458a44NOTdeleted/foo"));
+ EXPECT_TRUE(exists("b14b6458a44NOTdeleted/foo/file"));
+ EXPECT_TRUE(exists("b14b6458a44NOTdeleted/bar"));
+ EXPECT_TRUE(exists("b14b6458a44NOTdeleted/bar/file"));
+
+ EXPECT_TRUE(exists("com.example/foo"));
+ EXPECT_TRUE(exists("com.example/foo/file"));
+ EXPECT_TRUE(exists("com.example/bar"));
+ EXPECT_TRUE(exists("com.example/bar/file"));
+
+ EXPECT_TRUE(exists("==deleted==/foo"));
+ EXPECT_TRUE(exists("==deleted==/foo/file"));
+ EXPECT_TRUE(exists("==deleted==/bar"));
+ EXPECT_TRUE(exists("==deleted==/bar/file"));
+
+ EXPECT_TRUE(exists_renamed_deleted_dir());
+
+ service->cleanupInvalidPackageDirs(testUuid, 0, FLAG_STORAGE_CE | FLAG_STORAGE_DE);
+
+ EXPECT_EQ(::close(fd), 0);
+
+ EXPECT_FALSE(exists("5b14b6458a44==deleted==/foo"));
+ EXPECT_FALSE(exists("5b14b6458a44==deleted==/foo/file"));
+ EXPECT_FALSE(exists("5b14b6458a44==deleted==/bar"));
+ EXPECT_FALSE(exists("5b14b6458a44==deleted==/bar/file"));
+ EXPECT_FALSE(exists("5b14b6458a44==deleted==/bar/opened_file"));
+
+ EXPECT_TRUE(exists("b14b6458a44NOTdeleted/foo"));
+ EXPECT_TRUE(exists("b14b6458a44NOTdeleted/foo/file"));
+ EXPECT_TRUE(exists("b14b6458a44NOTdeleted/bar"));
+ EXPECT_TRUE(exists("b14b6458a44NOTdeleted/bar/file"));
+
+ EXPECT_TRUE(exists("com.example/foo"));
+ EXPECT_TRUE(exists("com.example/foo/file"));
+ EXPECT_TRUE(exists("com.example/bar"));
+ EXPECT_TRUE(exists("com.example/bar/file"));
+
+ EXPECT_FALSE(exists("==deleted==/foo"));
+ EXPECT_FALSE(exists("==deleted==/foo/file"));
+ EXPECT_FALSE(exists("==deleted==/bar"));
+ EXPECT_FALSE(exists("==deleted==/bar/file"));
+
+ EXPECT_FALSE(exists_renamed_deleted_dir());
+}
+
TEST_F(ServiceTest, HashSecondaryDex) {
LOG(INFO) << "HashSecondaryDex";
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 0f8a732..8a00be9 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -22,9 +22,10 @@
#include <stdlib.h>
#include <sys/capability.h>
#include <sys/stat.h>
+#include <sys/statvfs.h>
#include <sys/wait.h>
#include <sys/xattr.h>
-#include <sys/statvfs.h>
+#include <uuid/uuid.h>
#include <android-base/file.h>
#include <android-base/logging.h>
@@ -47,6 +48,7 @@
#define DEBUG_XATTRS 0
+using android::base::Dirname;
using android::base::EndsWith;
using android::base::Fdopendir;
using android::base::StringPrintf;
@@ -55,6 +57,10 @@
namespace android {
namespace installd {
+using namespace std::literals;
+
+static constexpr auto deletedSuffix = "==deleted=="sv;
+
/**
* Check that given string is valid filename, and that it attempts no
* parent or child directory traversal.
@@ -595,6 +601,93 @@
return res;
}
+static std::string make_unique_name(std::string_view suffix) {
+ static constexpr auto uuidStringSize = 36;
+
+ uuid_t guid;
+ uuid_generate(guid);
+
+ std::string name;
+ const auto suffixSize = suffix.size();
+ name.reserve(uuidStringSize + suffixSize);
+
+ name.resize(uuidStringSize);
+ uuid_unparse(guid, name.data());
+ name.append(suffix);
+
+ return name;
+}
+
+static int rename_delete_dir_contents(const std::string& pathname,
+ int (*exclusion_predicate)(const char*, const int),
+ bool ignore_if_missing) {
+ auto temp_dir_name = make_unique_name(deletedSuffix);
+ auto temp_dir_path =
+ base::StringPrintf("%s/%s", Dirname(pathname).c_str(), temp_dir_name.c_str());
+
+ if (::rename(pathname.c_str(), temp_dir_path.c_str())) {
+ if (ignore_if_missing && (errno == ENOENT)) {
+ return 0;
+ }
+ ALOGE("Couldn't rename %s -> %s: %s \n", pathname.c_str(), temp_dir_path.c_str(),
+ strerror(errno));
+ return -errno;
+ }
+
+ return delete_dir_contents(temp_dir_path.c_str(), 1, exclusion_predicate, ignore_if_missing);
+}
+
+bool is_renamed_deleted_dir(std::string_view path) {
+ return path.ends_with(deletedSuffix);
+}
+
+int rename_delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing) {
+ return rename_delete_dir_contents(pathname, nullptr, ignore_if_missing);
+}
+
+static auto open_dir(const char* dir) {
+ struct DirCloser {
+ void operator()(DIR* d) const noexcept { ::closedir(d); }
+ };
+ return std::unique_ptr<DIR, DirCloser>(::opendir(dir));
+}
+
+void cleanup_invalid_package_dirs_under_path(const std::string& pathname) {
+ auto dir = open_dir(pathname.c_str());
+ if (!dir) {
+ return;
+ }
+ int dfd = dirfd(dir.get());
+ if (dfd < 0) {
+ ALOGE("Couldn't dirfd %s: %s\n", pathname.c_str(), strerror(errno));
+ return;
+ }
+
+ struct dirent* de;
+ while ((de = readdir(dir.get()))) {
+ if (de->d_type != DT_DIR) {
+ continue;
+ }
+
+ std::string name{de->d_name};
+ // always skip "." and ".."
+ if (name == "." || name == "..") {
+ continue;
+ }
+
+ if (is_renamed_deleted_dir(name) || !is_valid_filename(name) ||
+ !is_valid_package_name(name)) {
+ ALOGI("Deleting renamed or invalid data directory: %s\n", name.c_str());
+ // Deleting the content.
+ delete_dir_contents_fd(dfd, name.c_str());
+ // Deleting the directory
+ if (unlinkat(dfd, name.c_str(), AT_REMOVEDIR) < 0) {
+ ALOGE("Couldn't unlinkat %s: %s\n", name.c_str(), strerror(errno));
+ }
+ }
+ }
+}
+
int delete_dir_contents_fd(int dfd, const char *name)
{
int fd, res;
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 549fc6c..ffde562 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -120,6 +120,11 @@
int delete_dir_contents(const std::string& pathname, bool ignore_if_missing = false);
int delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing = false);
+bool is_renamed_deleted_dir(std::string_view path);
+int rename_delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing = false);
+
+void cleanup_invalid_package_dirs_under_path(const std::string& pathname);
+
int delete_dir_contents(const char *pathname,
int also_delete_dir,
int (*exclusion_predicate)(const char *name, const int is_dir),
diff --git a/data/etc/android.software.window_magnification.xml b/data/etc/android.software.window_magnification.xml
new file mode 100644
index 0000000..10a2de1
--- /dev/null
+++ b/data/etc/android.software.window_magnification.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- This is the feature indicating device supports window magnifier.
+ And the hand-held and PC platform should support this.
+-->
+<permissions>
+ <feature name="android.software.window_magnification" />
+</permissions>
diff --git a/data/etc/go_handheld_core_hardware.xml b/data/etc/go_handheld_core_hardware.xml
index d601931..8df7fdb 100644
--- a/data/etc/go_handheld_core_hardware.xml
+++ b/data/etc/go_handheld_core_hardware.xml
@@ -46,6 +46,7 @@
<feature name="android.software.autofill" />
<feature name="android.software.cant_save_state" />
<feature name="android.software.secure_lock_screen" />
+ <feature name="android.software.window_magnification" />
<!-- Feature to specify if the device supports adding device admins. -->
<feature name="android.software.device_admin" />
diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
index 68b8def..8fdd8d0 100644
--- a/data/etc/handheld_core_hardware.xml
+++ b/data/etc/handheld_core_hardware.xml
@@ -54,6 +54,7 @@
<feature name="android.software.autofill" />
<feature name="android.software.cant_save_state" />
<feature name="android.software.secure_lock_screen" />
+ <feature name="android.software.window_magnification" />
<!-- Feature to specify if the device supports adding device admins. -->
<feature name="android.software.device_admin" />
diff --git a/data/etc/pc_core_hardware.xml b/data/etc/pc_core_hardware.xml
index b490ba0..3155710 100644
--- a/data/etc/pc_core_hardware.xml
+++ b/data/etc/pc_core_hardware.xml
@@ -49,6 +49,7 @@
<feature name="android.software.autofill" />
<feature name="android.software.cant_save_state" />
<feature name="android.software.secure_lock_screen" />
+ <feature name="android.software.window_magnification" />
<!-- Feature to specify if the device supports adding device admins. -->
<feature name="android.software.device_admin" />
@@ -62,4 +63,4 @@
<!-- Feature to specify if the device supports freeform. -->
<feature name="android.software.freeform_window_management" />
<feature name="android.hardware.type.pc" />
-</permissions>
\ No newline at end of file
+</permissions>
diff --git a/data/etc/tablet_core_hardware.xml b/data/etc/tablet_core_hardware.xml
index 8c369de..59d5b10 100644
--- a/data/etc/tablet_core_hardware.xml
+++ b/data/etc/tablet_core_hardware.xml
@@ -54,6 +54,7 @@
<feature name="android.software.autofill" />
<feature name="android.software.cant_save_state" />
<feature name="android.software.secure_lock_screen" />
+ <feature name="android.software.window_magnification" />
<!-- Feature to specify if the device supports adding device admins. -->
<feature name="android.software.device_admin" />
diff --git a/include/android/sensor.h b/include/android/sensor.h
index cf1ca02..c714b05 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -743,11 +743,36 @@
ASensorManager* ASensorManager_getInstanceForPackage(const char* packageName) __INTRODUCED_IN(26);
/**
- * Returns the list of available sensors.
+ * Returns the list of available sensors. The returned list is owned by the
+ * sensor manager and will not change between calls to this function.
+ *
+ * \param manager the {@link ASensorManager} instance obtained from
+ * {@link ASensorManager_getInstanceForPackage}.
+ * \param list the returned list of sensors.
+ * \return positive number of returned sensors or negative error code.
+ * BAD_VALUE: manager is NULL.
*/
int ASensorManager_getSensorList(ASensorManager* manager, ASensorList* list);
/**
+ * Returns the list of available dynamic sensors. If there are no dynamic
+ * sensors available, returns nullptr in list.
+ *
+ * Each time this is called, the previously returned list is deallocated and
+ * must no longer be used.
+ *
+ * Available since API level 33.
+ *
+ * \param manager the {@link ASensorManager} instance obtained from
+ * {@link ASensorManager_getInstanceForPackage}.
+ * \param list the returned list of dynamic sensors.
+ * \return positive number of returned sensors or negative error code.
+ * BAD_VALUE: manager is NULL.
+ */
+ssize_t ASensorManager_getDynamicSensorList(
+ ASensorManager* manager, ASensorList* list) __INTRODUCED_IN(33);
+
+/**
* Returns the default sensor for the given type, or NULL if no sensor
* of that type exists.
*/
diff --git a/include/ftl/Flags.h b/include/ftl/Flags.h
index 932af2d..708eaf5 100644
--- a/include/ftl/Flags.h
+++ b/include/ftl/Flags.h
@@ -120,10 +120,10 @@
}
/* Tests whether any of the given flags are set */
- bool any(Flags<F> f) { return (mFlags & f.mFlags) != 0; }
+ bool any(Flags<F> f) const { return (mFlags & f.mFlags) != 0; }
/* Tests whether all of the given flags are set */
- bool all(Flags<F> f) { return (mFlags & f.mFlags) == f.mFlags; }
+ bool all(Flags<F> f) const { return (mFlags & f.mFlags) == f.mFlags; }
Flags<F> operator|(Flags<F> rhs) const { return static_cast<F>(mFlags | rhs.mFlags); }
Flags<F>& operator|=(Flags<F> rhs) {
@@ -153,6 +153,10 @@
return *this;
}
+ inline Flags<F>& clear(Flags<F> f = static_cast<F>(~static_cast<U>(0))) {
+ return *this &= ~f;
+ }
+
Iterator begin() const { return Iterator(*this); }
Iterator end() const { return Iterator(); }
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 269b086..1821729 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -368,7 +368,7 @@
int32_t s = android_atomic_add(1, &mThreadPoolSeq);
pid_t pid = getpid();
String8 name;
- name.appendFormat("Binder:%d_%X", pid, s);
+ name.appendFormat("%d_%X:%s", pid, s, mDriverName.c_str());
return name;
}
diff --git a/libs/cputimeinstate/Android.bp b/libs/cputimeinstate/Android.bp
index 4f63194..79cc15f 100644
--- a/libs/cputimeinstate/Android.bp
+++ b/libs/cputimeinstate/Android.bp
@@ -13,12 +13,13 @@
shared_libs: [
"libbase",
"libbpf_bcc",
- "libbpf_android",
"libbpf_minimal",
"liblog",
- "libnetdutils"
],
- header_libs: ["bpf_prog_headers"],
+ header_libs: [
+ "bpf_prog_headers",
+ "bpf_headers",
+ ],
cflags: [
"-Werror",
"-Wall",
@@ -33,12 +34,13 @@
shared_libs: [
"libbase",
"libbpf_bcc",
- "libbpf_android",
"libbpf_minimal",
"libtimeinstate",
- "libnetdutils",
],
- header_libs: ["bpf_prog_headers"],
+ header_libs: [
+ "bpf_prog_headers",
+ "bpf_headers",
+ ],
cflags: [
"-Werror",
"-Wall",
diff --git a/libs/gralloc/OWNERS b/libs/gralloc/OWNERS
index 93879d8..72ff978 100644
--- a/libs/gralloc/OWNERS
+++ b/libs/gralloc/OWNERS
@@ -1 +1,4 @@
+# Graphics team
+alecmouri@google.com
chrisforbes@google.com
+jreck@google.com
\ No newline at end of file
diff --git a/libs/gralloc/types/Gralloc4.cpp b/libs/gralloc/types/Gralloc4.cpp
index 61e6657..68b99b0 100644
--- a/libs/gralloc/types/Gralloc4.cpp
+++ b/libs/gralloc/types/Gralloc4.cpp
@@ -196,6 +196,35 @@
status_t validateMetadataType(InputHidlVec* input, const MetadataType& expectedMetadataType);
/**
+ * Private helper functions
+ */
+template <class T>
+status_t encodeInteger(const T& input, OutputHidlVec* output) {
+ static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
+ std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
+ std::is_same<T, float>::value || std::is_same<T, double>::value);
+ if (!output) {
+ return BAD_VALUE;
+ }
+
+ const uint8_t* tmp = reinterpret_cast<const uint8_t*>(&input);
+ return output->encode(tmp, sizeof(input));
+}
+
+template <class T>
+status_t decodeInteger(InputHidlVec* input, T* output) {
+ static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
+ std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
+ std::is_same<T, float>::value || std::is_same<T, double>::value);
+ if (!output) {
+ return BAD_VALUE;
+ }
+
+ uint8_t* tmp = reinterpret_cast<uint8_t*>(output);
+ return input->decode(tmp, sizeof(*output));
+}
+
+/**
* encode/encodeMetadata are the main encoding functions. They take in T and uses the encodeHelper
* function to turn T into the hidl_vec byte stream.
*
@@ -251,10 +280,45 @@
template <class T>
status_t encodeOptionalMetadata(const MetadataType& metadataType, const std::optional<T>& input,
hidl_vec<uint8_t>* output, EncodeHelper<T> encodeHelper) {
- if (!input) {
- return NO_ERROR;
+ OutputHidlVec outputHidlVec{output};
+
+ status_t err = encodeMetadataType(metadataType, &outputHidlVec);
+ if (err) {
+ return err;
}
- return encodeMetadata(metadataType, *input, output, encodeHelper);
+
+ err = encodeInteger<uint32_t>(input.has_value() ? 1 : 0, &outputHidlVec);
+ if (err) {
+ return err;
+ }
+
+ if (input) {
+ err = encodeHelper(*input, &outputHidlVec);
+ if (err) {
+ return err;
+ }
+ }
+
+ err = outputHidlVec.resize();
+ if (err) {
+ return err;
+ }
+
+ err = encodeMetadataType(metadataType, &outputHidlVec);
+ if (err) {
+ return err;
+ }
+
+ err = encodeInteger<uint32_t>(input.has_value() ? 1 : 0, &outputHidlVec);
+ if (err) {
+ return err;
+ }
+
+ if (input) {
+ return encodeHelper(*input, &outputHidlVec);
+ }
+
+ return NO_ERROR;
}
/**
@@ -315,45 +379,36 @@
if (!output) {
return BAD_VALUE;
}
- if (input.size() <= 0) {
- output->reset();
- return NO_ERROR;
+
+ InputHidlVec inputHidlVec{&input};
+
+ status_t err = validateMetadataType(&inputHidlVec, metadataType);
+ if (err) {
+ return err;
}
- T tmp;
- status_t err = decodeMetadata(metadataType, input, &tmp, decodeHelper);
- if (!err) {
+
+ uint32_t present = 0;
+ err = decodeInteger<uint32_t>(&inputHidlVec, &present);
+ if (err) {
+ return err;
+ }
+
+ if (present) {
+ T tmp;
+ err = decodeHelper(&inputHidlVec, &tmp);
+ if (err) {
+ return err;
+ }
+
*output = tmp;
}
- return err;
-}
-/**
- * Private helper functions
- */
-template <class T>
-status_t encodeInteger(const T& input, OutputHidlVec* output) {
- static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
- std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
- std::is_same<T, float>::value || std::is_same<T, double>::value);
- if (!output) {
+ err = inputHidlVec.hasRemainingData();
+ if (err) {
return BAD_VALUE;
}
- const uint8_t* tmp = reinterpret_cast<const uint8_t*>(&input);
- return output->encode(tmp, sizeof(input));
-}
-
-template <class T>
-status_t decodeInteger(InputHidlVec* input, T* output) {
- static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
- std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
- std::is_same<T, float>::value || std::is_same<T, double>::value);
- if (!output) {
- return BAD_VALUE;
- }
-
- uint8_t* tmp = reinterpret_cast<uint8_t*>(output);
- return input->decode(tmp, sizeof(*output));
+ return NO_ERROR;
}
status_t encodeString(const std::string& input, OutputHidlVec* output) {
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index ec3587b..d634c58 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -37,6 +37,12 @@
"android.hardware.graphics.bufferqueue@2.0",
],
min_sdk_version: "29",
+ // TODO(b/218719284) can media use be constrained to libgui_bufferqueue_static?
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ "test_com.android.media.swcodec",
+ ],
}
cc_library_headers {
@@ -198,6 +204,7 @@
"SurfaceComposerClient.cpp",
"SyncFeatures.cpp",
"TransactionTracing.cpp",
+ "VsyncEventData.cpp",
"view/Surface.cpp",
"WindowInfosListenerReporter.cpp",
"bufferqueue/1.0/B2HProducerListener.cpp",
@@ -338,6 +345,7 @@
"android.hardware.graphics.bufferqueue@2.0",
"android.hardware.graphics.common@1.1",
"android.hardware.graphics.common@1.2",
+ "android.hardware.graphics.common-V3-ndk",
"android.hidl.token@1.0-utils",
"libbase",
"libcutils",
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index aeb237d..7ce72ff 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -842,6 +842,14 @@
mPendingTransactions.end());
}
+SurfaceComposerClient::Transaction* BLASTBufferQueue::gatherPendingTransactions(
+ uint64_t frameNumber) {
+ std::lock_guard _lock{mMutex};
+ SurfaceComposerClient::Transaction* t = new SurfaceComposerClient::Transaction();
+ mergePendingTransactions(t, frameNumber);
+ return t;
+}
+
// Maintains a single worker thread per process that services a list of runnables.
class AsyncWorker : public Singleton<AsyncWorker> {
private:
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index ee80082..39d380d 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -126,7 +126,7 @@
ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64
", displayId=%s, count=%d, vsyncId=%" PRId64,
this, ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount,
- vsyncEventData.id);
+ vsyncEventData.preferredVsyncId());
mWaitingForVsync = false;
mLastVsyncCount = vsyncCount;
dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData);
@@ -146,19 +146,6 @@
return 1; // keep the callback
}
-void DisplayEventDispatcher::populateFrameTimelines(const DisplayEventReceiver::Event& event,
- VsyncEventData* outVsyncEventData) const {
- for (size_t i = 0; i < DisplayEventReceiver::kFrameTimelinesLength; i++) {
- DisplayEventReceiver::Event::VSync::FrameTimeline receiverTimeline =
- event.vsync.frameTimelines[i];
- outVsyncEventData->frameTimelines[i] = {.id = receiverTimeline.vsyncId,
- .deadlineTimestamp =
- receiverTimeline.deadlineTimestamp,
- .expectedPresentTime =
- receiverTimeline.expectedVSyncTimestamp};
- }
-}
-
bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp,
PhysicalDisplayId* outDisplayId,
uint32_t* outCount,
@@ -179,12 +166,7 @@
*outTimestamp = ev.header.timestamp;
*outDisplayId = ev.header.displayId;
*outCount = ev.vsync.count;
- outVsyncEventData->id = ev.vsync.vsyncId;
- outVsyncEventData->deadlineTimestamp = ev.vsync.deadlineTimestamp;
- outVsyncEventData->frameInterval = ev.vsync.frameInterval;
- outVsyncEventData->preferredFrameTimelineIndex =
- ev.vsync.preferredFrameTimelineIndex;
- populateFrameTimelines(ev, outVsyncEventData);
+ *outVsyncEventData = ev.vsync.vsyncData;
break;
case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected);
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index b916e48..bfb7769 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -20,6 +20,7 @@
#include <gui/DisplayEventReceiver.h>
#include <gui/ISurfaceComposer.h>
+#include <gui/VsyncEventData.h>
#include <private/gui/ComposerService.h>
@@ -39,7 +40,13 @@
mEventConnection = sf->createDisplayEventConnection(vsyncSource, eventRegistration);
if (mEventConnection != nullptr) {
mDataChannel = std::make_unique<gui::BitTube>();
- mEventConnection->stealReceiveChannel(mDataChannel.get());
+ const auto status = mEventConnection->stealReceiveChannel(mDataChannel.get());
+ if (!status.isOk()) {
+ ALOGE("stealReceiveChannel failed: %s", status.toString8().c_str());
+ mInitError = std::make_optional<status_t>(status.transactionError());
+ mDataChannel.reset();
+ mEventConnection.clear();
+ }
}
}
}
@@ -50,12 +57,11 @@
status_t DisplayEventReceiver::initCheck() const {
if (mDataChannel != nullptr)
return NO_ERROR;
- return NO_INIT;
+ return mInitError.has_value() ? mInitError.value() : NO_INIT;
}
int DisplayEventReceiver::getFd() const {
- if (mDataChannel == nullptr)
- return NO_INIT;
+ if (mDataChannel == nullptr) return mInitError.has_value() ? mInitError.value() : NO_INIT;
return mDataChannel->getFd();
}
@@ -68,7 +74,7 @@
mEventConnection->setVsyncRate(count);
return NO_ERROR;
}
- return NO_INIT;
+ return mInitError.has_value() ? mInitError.value() : NO_INIT;
}
status_t DisplayEventReceiver::requestNextVsync() {
@@ -76,6 +82,19 @@
mEventConnection->requestNextVsync();
return NO_ERROR;
}
+ return mInitError.has_value() ? mInitError.value() : NO_INIT;
+}
+
+status_t DisplayEventReceiver::getLatestVsyncEventData(
+ ParcelableVsyncEventData* outVsyncEventData) const {
+ if (mEventConnection != nullptr) {
+ auto status = mEventConnection->getLatestVsyncEventData(outVsyncEventData);
+ if (!status.isOk()) {
+ ALOGE("Failed to get latest vsync event data: %s", status.exceptionMessage().c_str());
+ return status.transactionError();
+ }
+ return NO_ERROR;
+ }
return NO_INIT;
}
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index fb9ed22..75c5e26 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -42,6 +42,8 @@
// ---------------------------------------------------------------------------
+using namespace aidl::android::hardware::graphics;
+
namespace android {
using gui::IDisplayEventConnection;
@@ -1201,8 +1203,9 @@
return NO_ERROR;
}
- status_t getDisplayDecorationSupport(const sp<IBinder>& displayToken,
- bool* outSupport) const override {
+ status_t getDisplayDecorationSupport(
+ const sp<IBinder>& displayToken,
+ std::optional<common::DisplayDecorationSupport>* outSupport) const override {
Parcel data, reply;
status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
if (error != NO_ERROR) {
@@ -1225,7 +1228,26 @@
ALOGE("getDisplayDecorationSupport: failed to read support: %d", error);
return error;
}
- *outSupport = support;
+
+ if (support) {
+ int32_t format, alphaInterpretation;
+ error = reply.readInt32(&format);
+ if (error != NO_ERROR) {
+ ALOGE("getDisplayDecorationSupport: failed to read format: %d", error);
+ return error;
+ }
+ error = reply.readInt32(&alphaInterpretation);
+ if (error != NO_ERROR) {
+ ALOGE("getDisplayDecorationSupport: failed to read alphaInterpretation: %d", error);
+ return error;
+ }
+ outSupport->emplace();
+ outSupport->value().format = static_cast<common::PixelFormat>(format);
+ outSupport->value().alphaInterpretation =
+ static_cast<common::AlphaInterpretation>(alphaInterpretation);
+ } else {
+ outSupport->reset();
+ }
return NO_ERROR;
}
@@ -2164,14 +2186,18 @@
case GET_DISPLAY_DECORATION_SUPPORT: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> displayToken;
- status_t error = data.readNullableStrongBinder(&displayToken);
+ SAFE_PARCEL(data.readNullableStrongBinder, &displayToken);
+ std::optional<common::DisplayDecorationSupport> support;
+ auto error = getDisplayDecorationSupport(displayToken, &support);
if (error != NO_ERROR) {
- ALOGE("getDisplayDecorationSupport: failed to read display token: %d", error);
+ ALOGE("getDisplayDecorationSupport failed with error %d", error);
return error;
}
- bool support = false;
- error = getDisplayDecorationSupport(displayToken, &support);
- reply->writeBool(support);
+ reply->writeBool(support.has_value());
+ if (support) {
+ reply->writeInt32(static_cast<int32_t>(support.value().format));
+ reply->writeInt32(static_cast<int32_t>(support.value().alphaInterpretation));
+ }
return error;
}
case SET_FRAME_RATE: {
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index aa7ebc9..f7392d4 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -111,7 +111,14 @@
status_t SurfaceStats::writeToParcel(Parcel* output) const {
SAFE_PARCEL(output->writeStrongBinder, surfaceControl);
- SAFE_PARCEL(output->writeInt64, acquireTime);
+ if (const auto* acquireFence = std::get_if<sp<Fence>>(&acquireTimeOrFence)) {
+ SAFE_PARCEL(output->writeBool, true);
+ SAFE_PARCEL(output->write, **acquireFence);
+ } else {
+ SAFE_PARCEL(output->writeBool, false);
+ SAFE_PARCEL(output->writeInt64, std::get<nsecs_t>(acquireTimeOrFence));
+ }
+
if (previousReleaseFence) {
SAFE_PARCEL(output->writeBool, true);
SAFE_PARCEL(output->write, *previousReleaseFence);
@@ -131,10 +138,20 @@
status_t SurfaceStats::readFromParcel(const Parcel* input) {
SAFE_PARCEL(input->readStrongBinder, &surfaceControl);
- SAFE_PARCEL(input->readInt64, &acquireTime);
+
bool hasFence = false;
SAFE_PARCEL(input->readBool, &hasFence);
if (hasFence) {
+ acquireTimeOrFence = sp<Fence>::make();
+ SAFE_PARCEL(input->read, *std::get<sp<Fence>>(acquireTimeOrFence));
+ } else {
+ nsecs_t acquireTime;
+ SAFE_PARCEL(input->readInt64, &acquireTime);
+ acquireTimeOrFence = acquireTime;
+ }
+
+ SAFE_PARCEL(input->readBool, &hasFence);
+ if (hasFence) {
previousReleaseFence = new Fence();
SAFE_PARCEL(input->read, *previousReleaseFence);
}
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index eec4a87..9022e7d 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -35,7 +35,9 @@
using gui::WindowInfoHandle;
layer_state_t::layer_state_t()
- : what(0),
+ : surface(nullptr),
+ layerId(-1),
+ what(0),
x(0),
y(0),
z(0),
@@ -153,8 +155,12 @@
SAFE_PARCEL(output.writeBool, isTrustedOverlay);
SAFE_PARCEL(output.writeUint32, static_cast<uint32_t>(dropInputMode));
- SAFE_PARCEL(output.writeNullableParcelable,
- bufferData ? std::make_optional<BufferData>(*bufferData) : std::nullopt);
+
+ const bool hasBufferData = (bufferData != nullptr);
+ SAFE_PARCEL(output.writeBool, hasBufferData);
+ if (hasBufferData) {
+ SAFE_PARCEL(output.writeParcelable, *bufferData);
+ }
return NO_ERROR;
}
@@ -264,9 +270,15 @@
uint32_t mode;
SAFE_PARCEL(input.readUint32, &mode);
dropInputMode = static_cast<gui::DropInputMode>(mode);
- std::optional<BufferData> tmpBufferData;
- SAFE_PARCEL(input.readParcelable, &tmpBufferData);
- bufferData = tmpBufferData ? std::make_shared<BufferData>(*tmpBufferData) : nullptr;
+
+ bool hasBufferData;
+ SAFE_PARCEL(input.readBool, &hasBufferData);
+ if (hasBufferData) {
+ bufferData = std::make_shared<BufferData>();
+ SAFE_PARCEL(input.readParcelable, bufferData.get());
+ } else {
+ bufferData = nullptr;
+ }
return NO_ERROR;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 91b2fb1..9269c3e 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -52,6 +52,7 @@
namespace android {
+using aidl::android::hardware::graphics::common::DisplayDecorationSupport;
using gui::FocusRequest;
using gui::IRegionSamplingListener;
using gui::WindowInfo;
@@ -296,7 +297,7 @@
surfaceControlStats
.emplace_back(callbacksMap[callbackId]
.surfaceControls[surfaceStats.surfaceControl],
- transactionStats.latchTime, surfaceStats.acquireTime,
+ transactionStats.latchTime, surfaceStats.acquireTimeOrFence,
transactionStats.presentFence,
surfaceStats.previousReleaseFence, surfaceStats.transformHint,
surfaceStats.eventStats);
@@ -321,7 +322,7 @@
surfaceControlStats
.emplace_back(callbacksMap[callbackId]
.surfaceControls[surfaceStats.surfaceControl],
- transactionStats.latchTime, surfaceStats.acquireTime,
+ transactionStats.latchTime, surfaceStats.acquireTimeOrFence,
transactionStats.presentFence,
surfaceStats.previousReleaseFence, surfaceStats.transformHint,
surfaceStats.eventStats);
@@ -2239,8 +2240,9 @@
lightRadius);
}
-bool SurfaceComposerClient::getDisplayDecorationSupport(const sp<IBinder>& displayToken) {
- bool support = false;
+std::optional<DisplayDecorationSupport> SurfaceComposerClient::getDisplayDecorationSupport(
+ const sp<IBinder>& displayToken) {
+ std::optional<DisplayDecorationSupport> support;
ComposerService::getComposerService()->getDisplayDecorationSupport(displayToken, &support);
return support;
}
diff --git a/libs/gui/VsyncEventData.cpp b/libs/gui/VsyncEventData.cpp
new file mode 100644
index 0000000..23f0921
--- /dev/null
+++ b/libs/gui/VsyncEventData.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gui/VsyncEventData.h"
+#include <gui/DisplayEventReceiver.h>
+#include <private/gui/ParcelUtils.h>
+#include <utils/Log.h>
+#include <utils/Looper.h>
+#include <cstdint>
+
+namespace android::gui {
+
+int64_t VsyncEventData::preferredVsyncId() const {
+ return frameTimelines[preferredFrameTimelineIndex].vsyncId;
+}
+
+int64_t VsyncEventData::preferredDeadlineTimestamp() const {
+ return frameTimelines[preferredFrameTimelineIndex].deadlineTimestamp;
+}
+
+int64_t VsyncEventData::preferredExpectedPresentationTime() const {
+ return frameTimelines[preferredFrameTimelineIndex].expectedPresentationTime;
+}
+
+status_t ParcelableVsyncEventData::readFromParcel(const Parcel* parcel) {
+ if (parcel == nullptr) {
+ ALOGE("%s: Null parcel", __func__);
+ return BAD_VALUE;
+ }
+
+ SAFE_PARCEL(parcel->readInt64, &vsync.frameInterval);
+
+ uint64_t uintPreferredFrameTimelineIndex;
+ SAFE_PARCEL(parcel->readUint64, &uintPreferredFrameTimelineIndex);
+ vsync.preferredFrameTimelineIndex = static_cast<size_t>(uintPreferredFrameTimelineIndex);
+
+ for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
+ SAFE_PARCEL(parcel->readInt64, &vsync.frameTimelines[i].vsyncId);
+ SAFE_PARCEL(parcel->readInt64, &vsync.frameTimelines[i].deadlineTimestamp);
+ SAFE_PARCEL(parcel->readInt64, &vsync.frameTimelines[i].expectedPresentationTime);
+ }
+
+ return OK;
+}
+status_t ParcelableVsyncEventData::writeToParcel(Parcel* parcel) const {
+ SAFE_PARCEL(parcel->writeInt64, vsync.frameInterval);
+ SAFE_PARCEL(parcel->writeUint64, vsync.preferredFrameTimelineIndex);
+ for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
+ SAFE_PARCEL(parcel->writeInt64, vsync.frameTimelines[i].vsyncId);
+ SAFE_PARCEL(parcel->writeInt64, vsync.frameTimelines[i].deadlineTimestamp);
+ SAFE_PARCEL(parcel->writeInt64, vsync.frameTimelines[i].expectedPresentationTime);
+ }
+
+ return OK;
+}
+
+}; // namespace android::gui
diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp
index a866786..80bd638 100644
--- a/libs/gui/WindowInfo.cpp
+++ b/libs/gui/WindowInfo.cpp
@@ -18,7 +18,6 @@
#define LOG_TAG "WindowInfo"
#define LOG_NDEBUG 0
-#include <android-base/stringprintf.h>
#include <binder/Parcel.h>
#include <gui/WindowInfo.h>
@@ -27,6 +26,14 @@
namespace android::gui {
// --- WindowInfo ---
+void WindowInfo::setInputConfig(Flags<InputConfig> config, bool value) {
+ if (value) {
+ inputConfig |= config;
+ return;
+ }
+ inputConfig &= ~config;
+}
+
void WindowInfo::addTouchableRegion(const Rect& region) {
touchableRegion.orSelf(region);
}
@@ -40,7 +47,7 @@
}
bool WindowInfo::supportsSplitTouch() const {
- return flags.test(Flag::SPLIT_TOUCH);
+ return !inputConfig.test(InputConfig::PREVENT_SPLITTING);
}
bool WindowInfo::isSpy() const {
@@ -58,20 +65,19 @@
}
bool WindowInfo::operator==(const WindowInfo& info) const {
- return info.token == token && info.id == id && info.name == name && info.flags == flags &&
- info.type == type && info.dispatchingTimeout == dispatchingTimeout &&
- info.frameLeft == frameLeft && info.frameTop == frameTop &&
- info.frameRight == frameRight && info.frameBottom == frameBottom &&
- info.surfaceInset == surfaceInset && info.globalScaleFactor == globalScaleFactor &&
- info.transform == transform && info.touchableRegion.hasSameRects(touchableRegion) &&
- info.visible == visible && info.trustedOverlay == trustedOverlay &&
- info.focusable == focusable && info.touchOcclusionMode == touchOcclusionMode &&
- info.hasWallpaper == hasWallpaper && info.paused == paused &&
- info.ownerPid == ownerPid && info.ownerUid == ownerUid &&
- info.packageName == packageName && info.inputFeatures == inputFeatures &&
+ return info.token == token && info.id == id && info.name == name &&
+ info.dispatchingTimeout == dispatchingTimeout && info.frameLeft == frameLeft &&
+ info.frameTop == frameTop && info.frameRight == frameRight &&
+ info.frameBottom == frameBottom && info.surfaceInset == surfaceInset &&
+ info.globalScaleFactor == globalScaleFactor && info.transform == transform &&
+ info.touchableRegion.hasSameRects(touchableRegion) &&
+ info.touchOcclusionMode == touchOcclusionMode && info.ownerPid == ownerPid &&
+ info.ownerUid == ownerUid && info.packageName == packageName &&
+ info.inputFeatures == inputFeatures && info.inputConfig == inputConfig &&
info.displayId == displayId &&
info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop &&
- info.applicationInfo == applicationInfo;
+ info.applicationInfo == applicationInfo && info.layoutParamsType == layoutParamsType &&
+ info.layoutParamsFlags == layoutParamsFlags;
}
status_t WindowInfo::writeToParcel(android::Parcel* parcel) const {
@@ -85,13 +91,18 @@
}
parcel->writeInt32(1);
+ // Ensure that the size of the flags that we use is 32 bits for writing into the parcel.
+ static_assert(sizeof(inputFeatures) == 4u);
+ static_assert(sizeof(inputConfig) == 4u);
+
// clang-format off
status_t status = parcel->writeStrongBinder(token) ?:
parcel->writeInt64(dispatchingTimeout.count()) ?:
parcel->writeInt32(id) ?:
parcel->writeUtf8AsUtf16(name) ?:
- parcel->writeInt32(flags.get()) ?:
- parcel->writeInt32(static_cast<std::underlying_type_t<WindowInfo::Type>>(type)) ?:
+ parcel->writeInt32(layoutParamsFlags.get()) ?:
+ parcel->writeInt32(
+ static_cast<std::underlying_type_t<WindowInfo::Type>>(layoutParamsType)) ?:
parcel->writeInt32(frameLeft) ?:
parcel->writeInt32(frameTop) ?:
parcel->writeInt32(frameRight) ?:
@@ -105,16 +116,12 @@
parcel->writeFloat(transform.dtdy()) ?:
parcel->writeFloat(transform.dsdy()) ?:
parcel->writeFloat(transform.ty()) ?:
- parcel->writeBool(visible) ?:
- parcel->writeBool(focusable) ?:
- parcel->writeBool(hasWallpaper) ?:
- parcel->writeBool(paused) ?:
- parcel->writeBool(trustedOverlay) ?:
parcel->writeInt32(static_cast<int32_t>(touchOcclusionMode)) ?:
parcel->writeInt32(ownerPid) ?:
parcel->writeInt32(ownerUid) ?:
parcel->writeUtf8AsUtf16(packageName) ?:
parcel->writeInt32(inputFeatures.get()) ?:
+ parcel->writeInt32(inputConfig.get()) ?:
parcel->writeInt32(displayId) ?:
applicationInfo.writeToParcel(parcel) ?:
parcel->write(touchableRegion) ?:
@@ -141,8 +148,8 @@
return status;
}
- flags = Flags<Flag>(parcel->readInt32());
- type = static_cast<Type>(parcel->readInt32());
+ layoutParamsFlags = Flags<Flag>(parcel->readInt32());
+ layoutParamsType = static_cast<Type>(parcel->readInt32());
float dsdx, dtdx, tx, dtdy, dsdy, ty;
int32_t touchOcclusionModeInt;
// clang-format off
@@ -159,11 +166,6 @@
parcel->readFloat(&dtdy) ?:
parcel->readFloat(&dsdy) ?:
parcel->readFloat(&ty) ?:
- parcel->readBool(&visible) ?:
- parcel->readBool(&focusable) ?:
- parcel->readBool(&hasWallpaper) ?:
- parcel->readBool(&paused) ?:
- parcel->readBool(&trustedOverlay) ?:
parcel->readInt32(&touchOcclusionModeInt) ?:
parcel->readInt32(&ownerPid) ?:
parcel->readInt32(&ownerUid) ?:
@@ -177,6 +179,7 @@
touchOcclusionMode = static_cast<TouchOcclusionMode>(touchOcclusionModeInt);
inputFeatures = Flags<Feature>(parcel->readInt32());
+ inputConfig = Flags<InputConfig>(parcel->readInt32());
// clang-format off
status = parcel->readInt32(&displayId) ?:
applicationInfo.readFromParcel(parcel) ?:
diff --git a/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl b/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl
index 9f41593..9781ca9 100644
--- a/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl
+++ b/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl
@@ -17,6 +17,7 @@
package android.gui;
import android.gui.BitTube;
+import android.gui.ParcelableVsyncEventData;
/** @hide */
interface IDisplayEventConnection {
@@ -38,4 +39,9 @@
* requestNextVsync() schedules the next vsync event. It has no effect if the vsync rate is > 0.
*/
oneway void requestNextVsync(); // Asynchronous
+
+ /*
+ * getLatestVsyncEventData() gets the latest vsync event data.
+ */
+ ParcelableVsyncEventData getLatestVsyncEventData();
}
diff --git a/libs/gui/aidl/android/gui/ParcelableVsyncEventData.aidl b/libs/gui/aidl/android/gui/ParcelableVsyncEventData.aidl
new file mode 100644
index 0000000..ba76671
--- /dev/null
+++ b/libs/gui/aidl/android/gui/ParcelableVsyncEventData.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.gui;
+
+parcelable ParcelableVsyncEventData cpp_header "gui/VsyncEventData.h";
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index f77cfe6..1ed592b 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -98,6 +98,7 @@
void setSyncTransaction(SurfaceComposerClient::Transaction* t, bool acquireSingleBuffer = true);
void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber);
void applyPendingTransactions(uint64_t frameNumber);
+ SurfaceComposerClient::Transaction* gatherPendingTransactions(uint64_t frameNumber);
void update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height, int32_t format,
SurfaceComposerClient::Transaction* outTransaction = nullptr);
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index 40621dd..71968fa 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -17,45 +17,10 @@
#include <gui/DisplayEventReceiver.h>
#include <utils/Log.h>
#include <utils/Looper.h>
-#include <array>
namespace android {
using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride;
-struct VsyncEventData {
- // The Vsync Id corresponsing to this vsync event. This will be used to
- // populate ISurfaceComposer::setFrameTimelineVsync and
- // SurfaceComposerClient::setFrameTimelineVsync
- int64_t id = FrameTimelineInfo::INVALID_VSYNC_ID;
-
- // The deadline in CLOCK_MONOTONIC that the app needs to complete its
- // frame by (both on the CPU and the GPU)
- int64_t deadlineTimestamp = std::numeric_limits<int64_t>::max();
-
- // The current frame interval in ns when this frame was scheduled.
- int64_t frameInterval = 0;
-
- struct FrameTimeline {
- // The Vsync Id corresponsing to this vsync event. This will be used to
- // populate ISurfaceComposer::setFrameTimelineVsync and
- // SurfaceComposerClient::setFrameTimelineVsync
- int64_t id = FrameTimelineInfo::INVALID_VSYNC_ID;
-
- // The deadline in CLOCK_MONOTONIC that the app needs to complete its
- // frame by (both on the CPU and the GPU)
- int64_t deadlineTimestamp = std::numeric_limits<int64_t>::max();
-
- // The anticipated Vsync present time.
- int64_t expectedPresentTime = 0;
- };
-
- // Sorted possible frame timelines.
- std::array<FrameTimeline, DisplayEventReceiver::kFrameTimelinesLength> frameTimelines;
-
- // Index into the frameTimelines that represents the platform's preferred frame timeline.
- size_t preferredFrameTimelineIndex = std::numeric_limits<size_t>::max();
-};
-
class DisplayEventDispatcher : public LooperCallback {
public:
explicit DisplayEventDispatcher(
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index 456bbfb..cf7a4e5 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -26,6 +26,7 @@
#include <binder/IInterface.h>
#include <gui/ISurfaceComposer.h>
+#include <gui/VsyncEventData.h>
// ----------------------------------------------------------------------------
@@ -34,6 +35,8 @@
// ----------------------------------------------------------------------------
using gui::IDisplayEventConnection;
+using gui::ParcelableVsyncEventData;
+using gui::VsyncEventData;
namespace gui {
class BitTube;
@@ -49,8 +52,6 @@
// ----------------------------------------------------------------------------
class DisplayEventReceiver {
public:
- // Max amount of frame timelines is arbitrarily set to be reasonable.
- static constexpr int64_t kFrameTimelinesLength = 7;
enum {
DISPLAY_EVENT_VSYNC = fourcc('v', 's', 'y', 'n'),
@@ -76,16 +77,7 @@
struct VSync {
uint32_t count;
- nsecs_t expectedVSyncTimestamp __attribute__((aligned(8)));
- nsecs_t deadlineTimestamp __attribute__((aligned(8)));
- nsecs_t frameInterval __attribute__((aligned(8)));
- int64_t vsyncId;
- size_t preferredFrameTimelineIndex __attribute__((aligned(8)));
- struct FrameTimeline {
- nsecs_t expectedVSyncTimestamp __attribute__((aligned(8)));
- nsecs_t deadlineTimestamp __attribute__((aligned(8)));
- int64_t vsyncId;
- } frameTimelines[kFrameTimelinesLength];
+ VsyncEventData vsyncData;
};
struct Hotplug {
@@ -172,11 +164,22 @@
*/
status_t requestNextVsync();
+ /**
+ * getLatestVsyncEventData() gets the latest vsync event data.
+ */
+ status_t getLatestVsyncEventData(ParcelableVsyncEventData* outVsyncEventData) const;
+
private:
sp<IDisplayEventConnection> mEventConnection;
std::unique_ptr<gui::BitTube> mDataChannel;
+ std::optional<status_t> mInitError;
};
+inline bool operator==(DisplayEventReceiver::Event::FrameRateOverride lhs,
+ DisplayEventReceiver::Event::FrameRateOverride rhs) {
+ return (lhs.uid == rhs.uid) && std::abs(lhs.frameRateHz - rhs.frameRateHz) < 0.001f;
+}
+
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/gui/include/gui/HdrMetadata.h b/libs/gui/include/gui/HdrMetadata.h
index 1e9c3e7..0bdffac 100644
--- a/libs/gui/include/gui/HdrMetadata.h
+++ b/libs/gui/include/gui/HdrMetadata.h
@@ -44,6 +44,7 @@
status_t unflatten(void const* buffer, size_t size);
bool operator==(const HdrMetadata& rhs) const;
+ bool operator!=(const HdrMetadata& rhs) const { return !(*this == rhs); }
};
} // namespace android
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 90b2a0e..0a59f52 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -52,6 +52,8 @@
#include <unordered_set>
#include <vector>
+#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
+
namespace android {
struct client_cache_t;
@@ -533,15 +535,17 @@
* displayToken
* The token of the display.
* outSupport
- * An output parameter for whether the display supports
+ * An output parameter for whether/how the display supports
* DISPLAY_DECORATION layers.
*
* Returns NO_ERROR upon success. Otherwise,
* NAME_NOT_FOUND if the display is invalid, or
* BAD_VALUE if the output parameter is invalid.
*/
- virtual status_t getDisplayDecorationSupport(const sp<IBinder>& displayToken,
- bool* outSupport) const = 0;
+ virtual status_t getDisplayDecorationSupport(
+ const sp<IBinder>& displayToken,
+ std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
+ outSupport) const = 0;
/*
* Sets the intended frame rate for a surface. See ANativeWindow_setFrameRate() for more info.
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index 0df5822..a791c66 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -30,6 +30,7 @@
#include <cstdint>
#include <unordered_map>
#include <unordered_set>
+#include <variant>
namespace android {
@@ -130,12 +131,12 @@
status_t readFromParcel(const Parcel* input) override;
SurfaceStats() = default;
- SurfaceStats(const sp<IBinder>& sc, nsecs_t time, const sp<Fence>& prevReleaseFence,
- uint32_t hint, uint32_t currentMaxAcquiredBuffersCount,
- FrameEventHistoryStats frameEventStats, std::vector<JankData> jankData,
- ReleaseCallbackId previousReleaseCallbackId)
+ SurfaceStats(const sp<IBinder>& sc, std::variant<nsecs_t, sp<Fence>> acquireTimeOrFence,
+ const sp<Fence>& prevReleaseFence, uint32_t hint,
+ uint32_t currentMaxAcquiredBuffersCount, FrameEventHistoryStats frameEventStats,
+ std::vector<JankData> jankData, ReleaseCallbackId previousReleaseCallbackId)
: surfaceControl(sc),
- acquireTime(time),
+ acquireTimeOrFence(std::move(acquireTimeOrFence)),
previousReleaseFence(prevReleaseFence),
transformHint(hint),
currentMaxAcquiredBufferCount(currentMaxAcquiredBuffersCount),
@@ -144,7 +145,7 @@
previousReleaseCallbackId(previousReleaseCallbackId) {}
sp<IBinder> surfaceControl;
- nsecs_t acquireTime = -1;
+ std::variant<nsecs_t, sp<Fence>> acquireTimeOrFence = -1;
sp<Fence> previousReleaseFence;
uint32_t transformHint = 0;
uint32_t currentMaxAcquiredBufferCount = 0;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 61eeab3..25637ef 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -47,6 +47,8 @@
#include <gui/WindowInfosListenerReporter.h>
#include <math/vec3.h>
+#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
+
namespace android {
class HdrCapabilities;
@@ -58,12 +60,13 @@
using gui::IRegionSamplingListener;
struct SurfaceControlStats {
- SurfaceControlStats(const sp<SurfaceControl>& sc, nsecs_t latchTime, nsecs_t acquireTime,
+ SurfaceControlStats(const sp<SurfaceControl>& sc, nsecs_t latchTime,
+ std::variant<nsecs_t, sp<Fence>> acquireTimeOrFence,
const sp<Fence>& presentFence, const sp<Fence>& prevReleaseFence,
uint32_t hint, FrameEventHistoryStats eventStats)
: surfaceControl(sc),
latchTime(latchTime),
- acquireTime(acquireTime),
+ acquireTimeOrFence(std::move(acquireTimeOrFence)),
presentFence(presentFence),
previousReleaseFence(prevReleaseFence),
transformHint(hint),
@@ -71,7 +74,7 @@
sp<SurfaceControl> surfaceControl;
nsecs_t latchTime = -1;
- nsecs_t acquireTime = -1;
+ std::variant<nsecs_t, sp<Fence>> acquireTimeOrFence = -1;
sp<Fence> presentFence;
sp<Fence> previousReleaseFence;
uint32_t transformHint = 0;
@@ -285,14 +288,16 @@
float lightPosY, float lightPosZ, float lightRadius);
/*
- * Returns whether a display supports DISPLAY_DECORATION layers.
+ * Returns whether and how a display supports DISPLAY_DECORATION layers.
*
* displayToken
* The token of the display.
*
- * Returns whether a display supports DISPLAY_DECORATION layers.
+ * Returns how a display supports DISPLAY_DECORATION layers, or nullopt if
+ * it does not.
*/
- static bool getDisplayDecorationSupport(const sp<IBinder>& displayToken);
+ static std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>
+ getDisplayDecorationSupport(const sp<IBinder>& displayToken);
// ------------------------------------------------------------------------
// surface creation / destruction
diff --git a/libs/gui/include/gui/VsyncEventData.h b/libs/gui/include/gui/VsyncEventData.h
new file mode 100644
index 0000000..8e99539
--- /dev/null
+++ b/libs/gui/include/gui/VsyncEventData.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gui/FrameTimelineInfo.h>
+
+#include <array>
+
+namespace android::gui {
+// Plain Old Data (POD) vsync data structure. For example, it can be easily used in the
+// DisplayEventReceiver::Event union.
+struct VsyncEventData {
+ // Max amount of frame timelines is arbitrarily set to be reasonable.
+ static constexpr int64_t kFrameTimelinesLength = 7;
+
+ // The current frame interval in ns when this frame was scheduled.
+ int64_t frameInterval;
+
+ // Index into the frameTimelines that represents the platform's preferred frame timeline.
+ uint32_t preferredFrameTimelineIndex;
+
+ struct alignas(8) FrameTimeline {
+ // The Vsync Id corresponsing to this vsync event. This will be used to
+ // populate ISurfaceComposer::setFrameTimelineVsync and
+ // SurfaceComposerClient::setFrameTimelineVsync
+ int64_t vsyncId;
+
+ // The deadline in CLOCK_MONOTONIC in nanos that the app needs to complete its
+ // frame by (both on the CPU and the GPU).
+ int64_t deadlineTimestamp;
+
+ // The anticipated Vsync presentation time in nanos.
+ int64_t expectedPresentationTime;
+ } frameTimelines[kFrameTimelinesLength]; // Sorted possible frame timelines.
+
+ // Gets the preferred frame timeline's vsync ID.
+ int64_t preferredVsyncId() const;
+
+ // Gets the preferred frame timeline's deadline timestamp.
+ int64_t preferredDeadlineTimestamp() const;
+
+ // Gets the preferred frame timeline's expected vsync timestamp.
+ int64_t preferredExpectedPresentationTime() const;
+};
+
+struct ParcelableVsyncEventData : public Parcelable {
+ VsyncEventData vsync;
+
+ status_t readFromParcel(const Parcel*) override;
+ status_t writeToParcel(Parcel*) const override;
+};
+} // namespace android::gui
diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h
index eb64ac9..b9bffaa 100644
--- a/libs/gui/include/gui/WindowInfo.h
+++ b/libs/gui/include/gui/WindowInfo.h
@@ -151,6 +151,33 @@
// clang-format on
};
+ // Flags used to determine configuration of this input window.
+ // Input windows can be configured with two sets of flags: InputFeature (WindowInfo::Feature
+ // defined above), and InputConfig. When adding a new configuration for an input window:
+ // - If you are adding a new flag that's visible and accessible to apps, it should be added
+ // as an InputFeature.
+ // - If you are adding an internal behaviour that is used within the system or shell and is
+ // not exposed to apps, it should be added as an InputConfig.
+ enum class InputConfig : uint32_t {
+ // clang-format off
+ NONE = 0,
+ NOT_VISIBLE = 1 << 0,
+ NOT_FOCUSABLE = 1 << 1,
+ NOT_TOUCHABLE = 1 << 2,
+ PREVENT_SPLITTING = 1 << 3,
+ DUPLICATE_TOUCH_TO_WALLPAPER = 1 << 4,
+ IS_WALLPAPER = 1 << 5,
+ PAUSE_DISPATCHING = 1 << 6,
+ // This flag is set when the window is of a trusted type that is allowed to silently
+ // overlay other windows for the purpose of implementing the secure views feature.
+ // Trusted overlays, such as IME windows, can partly obscure other windows without causing
+ // motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED.
+ TRUSTED_OVERLAY = 1 << 7,
+ WATCH_OUTSIDE_TOUCH = 1 << 8,
+ SLIPPERY = 1 << 9,
+ // clang-format on
+ };
+
/* These values are filled in by the WM and passed through SurfaceFlinger
* unless specified otherwise.
*/
@@ -164,8 +191,6 @@
// This uniquely identifies the input window.
int32_t id = -1;
std::string name;
- Flags<Flag> flags;
- Type type = Type::UNKNOWN;
std::chrono::nanoseconds dispatchingTimeout = std::chrono::seconds(5);
/* These values are filled in by SurfaceFlinger. */
@@ -198,26 +223,24 @@
* to absolute coordinates by SurfaceFlinger once the frame is computed.
*/
Region touchableRegion;
- bool visible = false;
- bool focusable = false;
- bool hasWallpaper = false;
- bool paused = false;
- /* This flag is set when the window is of a trusted type that is allowed to silently
- * overlay other windows for the purpose of implementing the secure views feature.
- * Trusted overlays, such as IME windows, can partly obscure other windows without causing
- * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED.
- */
- bool trustedOverlay = false;
+
TouchOcclusionMode touchOcclusionMode = TouchOcclusionMode::BLOCK_UNTRUSTED;
int32_t ownerPid = -1;
int32_t ownerUid = -1;
std::string packageName;
Flags<Feature> inputFeatures;
+ Flags<InputConfig> inputConfig;
int32_t displayId = ADISPLAY_ID_NONE;
InputApplicationInfo applicationInfo;
bool replaceTouchableRegionWithCrop = false;
wp<IBinder> touchableRegionCropHandle;
+ // The window's layout params flags and type set by WM.
+ Type layoutParamsType = Type::UNKNOWN;
+ Flags<Flag> layoutParamsFlags;
+
+ void setInputConfig(Flags<InputConfig> config, bool value);
+
void addTouchableRegion(const Rect& region);
bool touchableRegionContainsPoint(int32_t x, int32_t y) const;
diff --git a/libs/gui/include/gui/test/CallbackUtils.h b/libs/gui/include/gui/test/CallbackUtils.h
index 6403208..62d1496 100644
--- a/libs/gui/include/gui/test/CallbackUtils.h
+++ b/libs/gui/include/gui/test/CallbackUtils.h
@@ -134,12 +134,15 @@
void verifySurfaceControlStats(const SurfaceControlStats& surfaceControlStats,
nsecs_t latchTime) const {
- const auto& [surfaceControl, latch, acquireTime, presentFence, previousReleaseFence,
- transformHint, frameEvents] = surfaceControlStats;
+ const auto& [surfaceControl, latch, acquireTimeOrFence, presentFence,
+ previousReleaseFence, transformHint, frameEvents] = surfaceControlStats;
- ASSERT_EQ(acquireTime > 0, mBufferResult == ExpectedResult::Buffer::ACQUIRED)
+ ASSERT_TRUE(std::holds_alternative<nsecs_t>(acquireTimeOrFence));
+ ASSERT_EQ(std::get<nsecs_t>(acquireTimeOrFence) > 0,
+ mBufferResult == ExpectedResult::Buffer::ACQUIRED)
<< "bad acquire time";
- ASSERT_LE(acquireTime, latchTime) << "acquire time should be <= latch time";
+ ASSERT_LE(std::get<nsecs_t>(acquireTimeOrFence), latchTime)
+ << "acquire time should be <= latch time";
if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::RELEASED) {
ASSERT_NE(previousReleaseFence, nullptr)
diff --git a/libs/gui/sysprop/Android.bp b/libs/gui/sysprop/Android.bp
index bddb0ac..cc33e4c 100644
--- a/libs/gui/sysprop/Android.bp
+++ b/libs/gui/sysprop/Android.bp
@@ -16,4 +16,9 @@
cpp: {
min_sdk_version: "29",
},
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ "test_com.android.media.swcodec",
+ ],
}
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 6dd1073..e58543a 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -44,6 +44,7 @@
"SurfaceTextureMultiContextGL_test.cpp",
"Surface_test.cpp",
"TextureRenderer.cpp",
+ "VsyncEventData_test.cpp",
"WindowInfo_test.cpp",
],
diff --git a/libs/gui/tests/DisplayEventStructLayout_test.cpp b/libs/gui/tests/DisplayEventStructLayout_test.cpp
index bcd39db..da88463 100644
--- a/libs/gui/tests/DisplayEventStructLayout_test.cpp
+++ b/libs/gui/tests/DisplayEventStructLayout_test.cpp
@@ -20,9 +20,10 @@
namespace android::test {
#define CHECK_OFFSET(type, member, expected_offset) \
- static_assert((offsetof(type, member) == (expected_offset)), "")
+ static_assert((offsetof(type, member) == (expected_offset)))
TEST(DisplayEventStructLayoutTest, TestEventAlignment) {
+ static_assert(std::is_pod<DisplayEventReceiver::Event::VSync>::value);
CHECK_OFFSET(DisplayEventReceiver::Event, vsync, 24);
CHECK_OFFSET(DisplayEventReceiver::Event, hotplug, 24);
CHECK_OFFSET(DisplayEventReceiver::Event, modeChange, 24);
@@ -32,10 +33,29 @@
CHECK_OFFSET(DisplayEventReceiver::Event::Header, timestamp, 16);
CHECK_OFFSET(DisplayEventReceiver::Event::VSync, count, 0);
- CHECK_OFFSET(DisplayEventReceiver::Event::VSync, expectedVSyncTimestamp, 8);
- CHECK_OFFSET(DisplayEventReceiver::Event::VSync, deadlineTimestamp, 16);
- CHECK_OFFSET(DisplayEventReceiver::Event::VSync, frameInterval, 24);
- CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncId, 32);
+ CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncData.frameInterval, 8);
+ CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncData.preferredFrameTimelineIndex, 16);
+ CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncData.frameTimelines, 24);
+ CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncData.frameTimelines[0].vsyncId, 24);
+ CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncData.frameTimelines[0].deadlineTimestamp,
+ 32);
+ CHECK_OFFSET(DisplayEventReceiver::Event::VSync,
+ vsyncData.frameTimelines[0].expectedPresentationTime, 40);
+ // Also test the offsets of the last frame timeline. A loop is not used because the non-const
+ // index cannot be used in static_assert.
+ const int lastFrameTimelineOffset = /* Start of array */ 24 +
+ (VsyncEventData::kFrameTimelinesLength - 1) * /* Size of FrameTimeline */ 24;
+ CHECK_OFFSET(DisplayEventReceiver::Event::VSync,
+ vsyncData.frameTimelines[VsyncEventData::kFrameTimelinesLength - 1].vsyncId,
+ lastFrameTimelineOffset);
+ CHECK_OFFSET(DisplayEventReceiver::Event::VSync,
+ vsyncData.frameTimelines[VsyncEventData::kFrameTimelinesLength - 1]
+ .deadlineTimestamp,
+ lastFrameTimelineOffset + 8);
+ CHECK_OFFSET(DisplayEventReceiver::Event::VSync,
+ vsyncData.frameTimelines[VsyncEventData::kFrameTimelinesLength - 1]
+ .expectedPresentationTime,
+ lastFrameTimelineOffset + 16);
CHECK_OFFSET(DisplayEventReceiver::Event::Hotplug, connected, 0);
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 06a0aca..fcfe21b 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -266,14 +266,8 @@
void populateInputInfo(int width, int height) {
mInputInfo.token = mClientChannel->getConnectionToken();
mInputInfo.name = "Test info";
- mInputInfo.flags = WindowInfo::Flag::NOT_TOUCH_MODAL;
- mInputInfo.type = WindowInfo::Type::BASE_APPLICATION;
mInputInfo.dispatchingTimeout = 5s;
mInputInfo.globalScaleFactor = 1.0;
- mInputInfo.focusable = true;
- mInputInfo.hasWallpaper = false;
- mInputInfo.paused = false;
-
mInputInfo.touchableRegion.orSelf(Rect(0, 0, width, height));
InputApplicationInfo aInfo;
@@ -750,7 +744,7 @@
// Add non touchable window to fully cover touchable window. Window behind gets touch, but
// with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED
std::unique_ptr<InputSurface> nonTouchableSurface = makeSurface(100, 100);
- nonTouchableSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
+ nonTouchableSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
nonTouchableSurface->mInputInfo.ownerUid = 22222;
// Overriding occlusion mode otherwise the touch would be discarded at InputDispatcher by
// the default obscured/untrusted touch filter introduced in S.
@@ -770,8 +764,8 @@
// AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED
std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100);
std::unique_ptr<InputSurface> nonTouchableSurface = makeSurface(100, 100);
- nonTouchableSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
- parentSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
+ nonTouchableSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
+ parentSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
nonTouchableSurface->mInputInfo.ownerUid = 22222;
parentSurface->mInputInfo.ownerUid = 22222;
nonTouchableSurface->showAt(0, 0);
@@ -794,8 +788,8 @@
// the touchable window. Window behind gets touch with no obscured flags.
std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100);
std::unique_ptr<InputSurface> nonTouchableSurface = makeSurface(100, 100);
- nonTouchableSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
- parentSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
+ nonTouchableSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
+ parentSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
nonTouchableSurface->mInputInfo.ownerUid = 22222;
parentSurface->mInputInfo.ownerUid = 22222;
nonTouchableSurface->showAt(0, 0);
@@ -815,7 +809,7 @@
std::unique_ptr<InputSurface> bufferSurface =
InputSurface::makeBufferInputSurface(mComposerClient, 0, 0);
- bufferSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
+ bufferSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
bufferSurface->mInputInfo.ownerUid = 22222;
surface->showAt(10, 10);
@@ -830,7 +824,7 @@
std::unique_ptr<BlastInputSurface> bufferSurface =
BlastInputSurface::makeBlastInputSurface(mComposerClient, 0, 0);
- bufferSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
+ bufferSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
bufferSurface->mInputInfo.ownerUid = 22222;
surface->showAt(10, 10);
@@ -883,7 +877,7 @@
[&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); });
surface->showAt(100, 100);
std::unique_ptr<InputSurface> obscuringSurface = makeSurface(100, 100);
- obscuringSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
+ obscuringSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
obscuringSurface->mInputInfo.ownerUid = 22222;
obscuringSurface->showAt(100, 100);
injectTap(101, 101);
@@ -902,7 +896,7 @@
[&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); });
surface->showAt(100, 100);
std::unique_ptr<InputSurface> obscuringSurface = makeSurface(100, 100);
- obscuringSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
+ obscuringSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
obscuringSurface->mInputInfo.ownerUid = 22222;
obscuringSurface->showAt(190, 190);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 120ed48..6056280 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -47,6 +47,7 @@
// retrieve wide-color and hdr settings from configstore
using namespace android::hardware::configstore;
using namespace android::hardware::configstore::V1_0;
+using aidl::android::hardware::graphics::common::DisplayDecorationSupport;
using gui::IDisplayEventConnection;
using gui::IRegionSamplingListener;
using ui::ColorMode;
@@ -889,8 +890,9 @@
return NO_ERROR;
}
- status_t getDisplayDecorationSupport(const sp<IBinder>& /*displayToken*/,
- bool* /*outSupport*/) const override {
+ status_t getDisplayDecorationSupport(
+ const sp<IBinder>& /*displayToken*/,
+ std::optional<DisplayDecorationSupport>* /*outSupport*/) const override {
return NO_ERROR;
}
diff --git a/libs/gui/tests/VsyncEventData_test.cpp b/libs/gui/tests/VsyncEventData_test.cpp
new file mode 100644
index 0000000..f114522
--- /dev/null
+++ b/libs/gui/tests/VsyncEventData_test.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <binder/Parcel.h>
+
+#include <gui/VsyncEventData.h>
+
+namespace android {
+
+using gui::ParcelableVsyncEventData;
+using gui::VsyncEventData;
+using FrameTimeline = gui::VsyncEventData::FrameTimeline;
+
+namespace test {
+
+TEST(ParcelableVsyncEventData, Parcelling) {
+ ParcelableVsyncEventData data;
+ data.vsync.frameInterval = 789;
+ data.vsync.preferredFrameTimelineIndex = 1;
+ FrameTimeline timeline0 = FrameTimeline{1, 2, 3};
+ FrameTimeline timeline1 = FrameTimeline{4, 5, 6};
+ data.vsync.frameTimelines[0] = timeline0;
+ data.vsync.frameTimelines[1] = timeline1;
+
+ Parcel p;
+ data.writeToParcel(&p);
+ p.setDataPosition(0);
+
+ ParcelableVsyncEventData data2;
+ data2.readFromParcel(&p);
+ ASSERT_EQ(data.vsync.frameInterval, data2.vsync.frameInterval);
+ ASSERT_EQ(data.vsync.preferredFrameTimelineIndex, data2.vsync.preferredFrameTimelineIndex);
+ for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
+ ASSERT_EQ(data.vsync.frameTimelines[i].vsyncId, data2.vsync.frameTimelines[i].vsyncId);
+ ASSERT_EQ(data.vsync.frameTimelines[i].deadlineTimestamp,
+ data2.vsync.frameTimelines[i].deadlineTimestamp);
+ ASSERT_EQ(data.vsync.frameTimelines[i].expectedPresentationTime,
+ data2.vsync.frameTimelines[i].expectedPresentationTime);
+ }
+}
+
+} // namespace test
+} // namespace android
diff --git a/libs/gui/tests/WindowInfo_test.cpp b/libs/gui/tests/WindowInfo_test.cpp
index ff3ba2a..ff9bae2 100644
--- a/libs/gui/tests/WindowInfo_test.cpp
+++ b/libs/gui/tests/WindowInfo_test.cpp
@@ -49,8 +49,8 @@
i.windowToken = new BBinder();
i.id = 1;
i.name = "Foobar";
- i.flags = WindowInfo::Flag::SLIPPERY;
- i.type = WindowInfo::Type::INPUT_METHOD;
+ i.layoutParamsFlags = WindowInfo::Flag::SLIPPERY;
+ i.layoutParamsType = WindowInfo::Type::INPUT_METHOD;
i.dispatchingTimeout = 12s;
i.frameLeft = 93;
i.frameTop = 34;
@@ -60,15 +60,12 @@
i.globalScaleFactor = 0.3;
i.alpha = 0.7;
i.transform.set({0.4, -1, 100, 0.5, 0, 40, 0, 0, 1});
- i.visible = false;
- i.focusable = false;
- i.hasWallpaper = false;
- i.paused = false;
i.touchOcclusionMode = TouchOcclusionMode::ALLOW;
i.ownerPid = 19;
i.ownerUid = 24;
i.packageName = "com.example.package";
i.inputFeatures = WindowInfo::Feature::DISABLE_USER_ACTIVITY;
+ i.inputConfig = WindowInfo::InputConfig::NOT_FOCUSABLE;
i.displayId = 34;
i.replaceTouchableRegionWithCrop = true;
i.touchableRegionCropHandle = touchableRegionCropHandle;
@@ -85,8 +82,8 @@
ASSERT_EQ(i.windowToken, i2.windowToken);
ASSERT_EQ(i.id, i2.id);
ASSERT_EQ(i.name, i2.name);
- ASSERT_EQ(i.flags, i2.flags);
- ASSERT_EQ(i.type, i2.type);
+ ASSERT_EQ(i.layoutParamsFlags, i2.layoutParamsFlags);
+ ASSERT_EQ(i.layoutParamsType, i2.layoutParamsType);
ASSERT_EQ(i.dispatchingTimeout, i2.dispatchingTimeout);
ASSERT_EQ(i.frameLeft, i2.frameLeft);
ASSERT_EQ(i.frameTop, i2.frameTop);
@@ -96,15 +93,12 @@
ASSERT_EQ(i.globalScaleFactor, i2.globalScaleFactor);
ASSERT_EQ(i.alpha, i2.alpha);
ASSERT_EQ(i.transform, i2.transform);
- ASSERT_EQ(i.visible, i2.visible);
- ASSERT_EQ(i.focusable, i2.focusable);
- ASSERT_EQ(i.hasWallpaper, i2.hasWallpaper);
- ASSERT_EQ(i.paused, i2.paused);
ASSERT_EQ(i.touchOcclusionMode, i2.touchOcclusionMode);
ASSERT_EQ(i.ownerPid, i2.ownerPid);
ASSERT_EQ(i.ownerUid, i2.ownerUid);
ASSERT_EQ(i.packageName, i2.packageName);
ASSERT_EQ(i.inputFeatures, i2.inputFeatures);
+ ASSERT_EQ(i.inputConfig, i2.inputConfig);
ASSERT_EQ(i.displayId, i2.displayId);
ASSERT_EQ(i.replaceTouchableRegionWithCrop, i2.replaceTouchableRegionWithCrop);
ASSERT_EQ(i.touchableRegionCropHandle, i2.touchableRegionCropHandle);
diff --git a/libs/nativebase/Android.bp b/libs/nativebase/Android.bp
index 1a4729c..77b23db 100644
--- a/libs/nativebase/Android.bp
+++ b/libs/nativebase/Android.bp
@@ -45,5 +45,9 @@
enabled: true,
},
},
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
min_sdk_version: "29",
}
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index d90ee57..3ce381b 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -73,6 +73,7 @@
} // namespace
namespace android {
+using gui::VsyncEventData;
struct FrameCallback {
AChoreographer_frameCallback callback;
@@ -102,10 +103,7 @@
struct ChoreographerFrameCallbackDataImpl {
int64_t frameTimeNanos{0};
- std::array<VsyncEventData::FrameTimeline, DisplayEventReceiver::kFrameTimelinesLength>
- frameTimelines;
-
- size_t preferredFrameTimelineIndex;
+ VsyncEventData vsyncEventData;
const Choreographer* choreographer;
};
@@ -450,8 +448,7 @@
ChoreographerFrameCallbackDataImpl Choreographer::createFrameCallbackData(nsecs_t timestamp) const {
return {.frameTimeNanos = timestamp,
- .preferredFrameTimelineIndex = mLastVsyncEventData.preferredFrameTimelineIndex,
- .frameTimelines = mLastVsyncEventData.frameTimelines,
+ .vsyncEventData = mLastVsyncEventData,
.choreographer = this};
}
@@ -634,7 +631,7 @@
AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
"Data is only valid in callback");
- return frameCallbackData->frameTimelines.size();
+ return VsyncEventData::kFrameTimelinesLength;
}
size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex(
const AChoreographerFrameCallbackData* data) {
@@ -642,7 +639,7 @@
AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
"Data is only valid in callback");
- return frameCallbackData->preferredFrameTimelineIndex;
+ return frameCallbackData->vsyncEventData.preferredFrameTimelineIndex;
}
AVsyncId AChoreographerFrameCallbackData_getFrameTimelineVsyncId(
const AChoreographerFrameCallbackData* data, size_t index) {
@@ -650,8 +647,8 @@
AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
"Data is only valid in callback");
- LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds");
- return frameCallbackData->frameTimelines[index].id;
+ LOG_ALWAYS_FATAL_IF(index >= VsyncEventData::kFrameTimelinesLength, "Index out of bounds");
+ return frameCallbackData->vsyncEventData.frameTimelines[index].vsyncId;
}
int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTimeNanos(
const AChoreographerFrameCallbackData* data, size_t index) {
@@ -659,8 +656,8 @@
AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
"Data is only valid in callback");
- LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds");
- return frameCallbackData->frameTimelines[index].expectedPresentTime;
+ LOG_ALWAYS_FATAL_IF(index >= VsyncEventData::kFrameTimelinesLength, "Index out of bounds");
+ return frameCallbackData->vsyncEventData.frameTimelines[index].expectedPresentationTime;
}
int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos(
const AChoreographerFrameCallbackData* data, size_t index) {
@@ -668,8 +665,8 @@
AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
"Data is only valid in callback");
- LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds");
- return frameCallbackData->frameTimelines[index].deadlineTimestamp;
+ LOG_ALWAYS_FATAL_IF(index >= VsyncEventData::kFrameTimelinesLength, "Index out of bounds");
+ return frameCallbackData->vsyncEventData.frameTimelines[index].deadlineTimestamp;
}
AChoreographer* AChoreographer_create() {
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 9286009..d30efa1 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -47,6 +47,11 @@
// TODO(b/153609531): remove when no longer needed.
native_bridge_supported: true,
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ "test_com.android.media.swcodec",
+ ],
host_supported: true,
}
@@ -64,7 +69,7 @@
symbol_file: "libnativewindow.map.txt",
unversioned: true,
override_export_include_dirs: [
- "include"
+ "include",
],
},
export_include_dirs: [
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index faa84fc..3e7f69c 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -194,6 +194,8 @@
// Returns the tid of the renderengine thread if it's threaded, and std::nullopt otherwise
virtual std::optional<pid_t> getRenderEngineTid() const { return std::nullopt; }
+ virtual void setEnableTracing(bool /*tracingEnabled*/) {}
+
protected:
RenderEngine() : RenderEngine(RenderEngineType::GLES) {}
diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp
index 29175a2..1fb24f5 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaRenderEngine.cpp
@@ -20,15 +20,15 @@
#include "SkiaRenderEngine.h"
-#include <android-base/properties.h>
#include <src/core/SkTraceEventCommon.h>
namespace android {
namespace renderengine {
namespace skia {
-SkiaRenderEngine::SkiaRenderEngine(RenderEngineType type) : RenderEngine(type) {
- SkAndroidFrameworkTraceUtil::setEnableTracing(
- base::GetBoolProperty(PROPERTY_SKIA_ATRACE_ENABLED, false));
+SkiaRenderEngine::SkiaRenderEngine(RenderEngineType type) : RenderEngine(type) {}
+
+void SkiaRenderEngine::setEnableTracing(bool tracingEnabled) {
+ SkAndroidFrameworkTraceUtil::setEnableTracing(tracingEnabled);
}
} // namespace skia
} // namespace renderengine
diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h
index eb65e83..5d10b6f 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.h
+++ b/libs/renderengine/skia/SkiaRenderEngine.h
@@ -47,6 +47,7 @@
virtual int getContextPriority() override { return 0; }
virtual void assertShadersCompiled(int numShaders) {}
virtual int reportShadersCompiled() { return 0; }
+ virtual void setEnableTracing(bool tracingEnabled) override;
protected:
virtual void mapExternalTextureBuffer(const sp<GraphicBuffer>& /*buffer*/,
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp
index a7176d3..203bb54 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.cpp
+++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp
@@ -403,6 +403,18 @@
return std::make_optional(tidFuture.get());
}
+void RenderEngineThreaded::setEnableTracing(bool tracingEnabled) {
+ // This function is designed so it can run asynchronously, so we do not need to wait
+ // for the futures.
+ {
+ std::lock_guard lock(mThreadMutex);
+ mFunctionCalls.push([tracingEnabled](renderengine::RenderEngine& instance) {
+ ATRACE_NAME("REThreaded::setEnableTracing");
+ instance.setEnableTracing(tracingEnabled);
+ });
+ }
+ mCondition.notify_one();
+}
} // namespace threaded
} // namespace renderengine
} // namespace android
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h
index 1ba72dd..1340902 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.h
+++ b/libs/renderengine/threaded/RenderEngineThreaded.h
@@ -67,6 +67,7 @@
bool supportsBackgroundBlur() override;
void onActiveDisplaySizeChanged(ui::Size size) override;
std::optional<pid_t> getRenderEngineTid() const override;
+ void setEnableTracing(bool tracingEnabled) override;
protected:
void mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, bool isRenderable) override;
diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp
index 62f4b4e..0ba9704 100644
--- a/libs/sensor/SensorManager.cpp
+++ b/libs/sensor/SensorManager.cpp
@@ -100,6 +100,7 @@
SensorManager::~SensorManager() {
free(mSensorList);
+ free(mDynamicSensorList);
}
status_t SensorManager::waitForSensorService(sp<ISensorServer> *server) {
@@ -130,6 +131,9 @@
free(mSensorList);
mSensorList = nullptr;
mSensors.clear();
+ free(mDynamicSensorList);
+ mDynamicSensorList = nullptr;
+ mDynamicSensors.clear();
}
status_t SensorManager::assertStateLocked() {
@@ -197,6 +201,35 @@
return static_cast<ssize_t>(count);
}
+ssize_t SensorManager::getDynamicSensorList(Sensor const* const** list) {
+ Mutex::Autolock _l(mLock);
+ status_t err = assertStateLocked();
+ if (err < 0) {
+ return static_cast<ssize_t>(err);
+ }
+
+ free(mDynamicSensorList);
+ mDynamicSensorList = nullptr;
+ mDynamicSensors = mSensorServer->getDynamicSensorList(mOpPackageName);
+ size_t dynamicCount = mDynamicSensors.size();
+ if (dynamicCount > 0) {
+ mDynamicSensorList = static_cast<Sensor const**>(
+ malloc(dynamicCount * sizeof(Sensor*)));
+ if (mDynamicSensorList == nullptr) {
+ ALOGE("Failed to allocate dynamic sensor list for %zu sensors.",
+ dynamicCount);
+ return static_cast<ssize_t>(NO_MEMORY);
+ }
+
+ for (size_t i = 0; i < dynamicCount; i++) {
+ mDynamicSensorList[i] = mDynamicSensors.array() + i;
+ }
+ }
+
+ *list = mDynamicSensorList;
+ return static_cast<ssize_t>(mDynamicSensors.size());
+}
+
Sensor const* SensorManager::getDefaultSensor(int type)
{
Mutex::Autolock _l(mLock);
diff --git a/libs/sensor/include/sensor/SensorManager.h b/libs/sensor/include/sensor/SensorManager.h
index 09ac7ed..8d0a8a4 100644
--- a/libs/sensor/include/sensor/SensorManager.h
+++ b/libs/sensor/include/sensor/SensorManager.h
@@ -58,6 +58,7 @@
ssize_t getSensorList(Sensor const* const** list);
ssize_t getDynamicSensorList(Vector<Sensor>& list);
+ ssize_t getDynamicSensorList(Sensor const* const** list);
Sensor const* getDefaultSensor(int type);
sp<SensorEventQueue> createEventQueue(
String8 packageName = String8(""), int mode = 0, String16 attributionTag = String16(""));
@@ -83,6 +84,8 @@
sp<ISensorServer> mSensorServer;
Sensor const** mSensorList;
Vector<Sensor> mSensors;
+ Sensor const** mDynamicSensorList = nullptr;
+ Vector<Sensor> mDynamicSensors;
sp<IBinder::DeathRecipient> mDeathObserver;
const String16 mOpPackageName;
std::unordered_map<int, sp<ISensorEventConnection>> mDirectConnection;
diff --git a/libs/sensorprivacy/SensorPrivacyManager.cpp b/libs/sensorprivacy/SensorPrivacyManager.cpp
index ef3ceda..2be98e7 100644
--- a/libs/sensorprivacy/SensorPrivacyManager.cpp
+++ b/libs/sensorprivacy/SensorPrivacyManager.cpp
@@ -55,12 +55,12 @@
return service;
}
-bool SensorPrivacyManager::supportsSensorToggle(int sensor) {
+bool SensorPrivacyManager::supportsSensorToggle(int toggleType, int sensor) {
if (mSupportedCache.find(sensor) == mSupportedCache.end()) {
sp<hardware::ISensorPrivacyManager> service = getService();
if (service != nullptr) {
bool result;
- service->supportsSensorToggle(sensor, &result);
+ service->supportsSensorToggle(toggleType, sensor, &result);
mSupportedCache[sensor] = result;
return result;
}
@@ -80,12 +80,12 @@
}
}
-status_t SensorPrivacyManager::addIndividualSensorPrivacyListener(int userId, int sensor,
+status_t SensorPrivacyManager::addToggleSensorPrivacyListener(
const sp<hardware::ISensorPrivacyListener>& listener)
{
sp<hardware::ISensorPrivacyManager> service = getService();
if (service != nullptr) {
- return service->addIndividualSensorPrivacyListener(userId, sensor, listener)
+ return service->addToggleSensorPrivacyListener(listener)
.transactionError();
}
return UNEXPECTED_NULL;
@@ -100,12 +100,12 @@
}
}
-void SensorPrivacyManager::removeIndividualSensorPrivacyListener(int sensor,
+void SensorPrivacyManager::removeToggleSensorPrivacyListener(
const sp<hardware::ISensorPrivacyListener>& listener)
{
sp<hardware::ISensorPrivacyManager> service = getService();
if (service != nullptr) {
- service->removeIndividualSensorPrivacyListener(sensor, listener);
+ service->removeToggleSensorPrivacyListener(listener);
}
}
@@ -121,24 +121,36 @@
return false;
}
-bool SensorPrivacyManager::isIndividualSensorPrivacyEnabled(int userId, int sensor)
+bool SensorPrivacyManager::isToggleSensorPrivacyEnabled(int sensor)
{
- sp<hardware::ISensorPrivacyManager> service = getService();
+ sp<hardware::ISensorPrivacyManager> service = getService();
if (service != nullptr) {
bool result;
- service->isIndividualSensorPrivacyEnabled(userId, sensor, &result);
+ service->isCombinedToggleSensorPrivacyEnabled(sensor, &result);
return result;
}
// if the SensorPrivacyManager is not available then assume sensor privacy is disabled
return false;
}
-status_t SensorPrivacyManager::isIndividualSensorPrivacyEnabled(int userId, int sensor,
+bool SensorPrivacyManager::isToggleSensorPrivacyEnabled(int toggleType, int sensor)
+{
+ sp<hardware::ISensorPrivacyManager> service = getService();
+ if (service != nullptr) {
+ bool result;
+ service->isToggleSensorPrivacyEnabled(toggleType, sensor, &result);
+ return result;
+ }
+ // if the SensorPrivacyManager is not available then assume sensor privacy is disabled
+ return false;
+}
+
+status_t SensorPrivacyManager::isToggleSensorPrivacyEnabled(int toggleType, int sensor,
bool &returnVal)
{
sp<hardware::ISensorPrivacyManager> service = getService();
if (service != nullptr) {
- binder::Status res = service->isIndividualSensorPrivacyEnabled(userId, sensor, &returnVal);
+ binder::Status res = service->isToggleSensorPrivacyEnabled(toggleType, sensor, &returnVal);
return res.transactionError();
}
// if the SensorPrivacyManager is not available then assume sensor privacy is disabled
diff --git a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyListener.aidl b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyListener.aidl
index 58177d8..eccd54c 100644
--- a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyListener.aidl
+++ b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyListener.aidl
@@ -20,5 +20,5 @@
* @hide
*/
oneway interface ISensorPrivacyListener {
- void onSensorPrivacyChanged(boolean enabled);
+ void onSensorPrivacyChanged(int toggleType, int sensor, boolean enabled);
}
diff --git a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
index 9564cba..49a1e1e 100644
--- a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
+++ b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
@@ -20,23 +20,25 @@
/** @hide */
interface ISensorPrivacyManager {
- boolean supportsSensorToggle(int sensor);
+ boolean supportsSensorToggle(int toggleType, int sensor);
void addSensorPrivacyListener(in ISensorPrivacyListener listener);
- void addIndividualSensorPrivacyListener(int userId, int sensor, in ISensorPrivacyListener listener);
+ void addToggleSensorPrivacyListener(in ISensorPrivacyListener listener);
void removeSensorPrivacyListener(in ISensorPrivacyListener listener);
- void removeIndividualSensorPrivacyListener(int sensor, in ISensorPrivacyListener listener);
+ void removeToggleSensorPrivacyListener(in ISensorPrivacyListener listener);
boolean isSensorPrivacyEnabled();
- boolean isIndividualSensorPrivacyEnabled(int userId, int sensor);
+ boolean isCombinedToggleSensorPrivacyEnabled(int sensor);
+
+ boolean isToggleSensorPrivacyEnabled(int toggleType, int sensor);
void setSensorPrivacy(boolean enable);
- void setIndividualSensorPrivacy(int userId, int source, int sensor, boolean enable);
+ void setToggleSensorPrivacy(int userId, int source, int sensor, boolean enable);
- void setIndividualSensorPrivacyForProfileGroup(int userId, int source, int sensor, boolean enable);
+ void setToggleSensorPrivacyForProfileGroup(int userId, int source, int sensor, boolean enable);
}
diff --git a/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h b/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
index af699d0..fc5fdf7 100644
--- a/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
+++ b/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
@@ -31,22 +31,26 @@
{
public:
enum {
- INDIVIDUAL_SENSOR_MICROPHONE = 1,
- INDIVIDUAL_SENSOR_CAMERA = 2
+ TOGGLE_SENSOR_MICROPHONE = 1,
+ TOGGLE_SENSOR_CAMERA = 2
+ };
+
+ enum {
+ TOGGLE_TYPE_SOFTWARE = 1,
+ TOGGLE_TYPE_HARDWARE = 2
};
SensorPrivacyManager();
- bool supportsSensorToggle(int sensor);
+ bool supportsSensorToggle(int toggleType, int sensor);
void addSensorPrivacyListener(const sp<hardware::ISensorPrivacyListener>& listener);
- status_t addIndividualSensorPrivacyListener(int userId, int sensor,
- const sp<hardware::ISensorPrivacyListener>& listener);
+ status_t addToggleSensorPrivacyListener(const sp<hardware::ISensorPrivacyListener>& listener);
void removeSensorPrivacyListener(const sp<hardware::ISensorPrivacyListener>& listener);
- void removeIndividualSensorPrivacyListener(int sensor,
- const sp<hardware::ISensorPrivacyListener>& listener);
+ void removeToggleSensorPrivacyListener(const sp<hardware::ISensorPrivacyListener>& listener);
bool isSensorPrivacyEnabled();
- bool isIndividualSensorPrivacyEnabled(int userId, int sensor);
- status_t isIndividualSensorPrivacyEnabled(int userId, int sensor, bool &result);
+ bool isToggleSensorPrivacyEnabled(int sensor);
+ bool isToggleSensorPrivacyEnabled(int toggleType, int sensor);
+ status_t isToggleSensorPrivacyEnabled(int toggleType, int sensor, bool &result);
status_t linkToDeath(const sp<IBinder::DeathRecipient>& recipient);
status_t unlinkToDeath(const sp<IBinder::DeathRecipient>& recipient);
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index f5a22ec..a9380c6 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -235,6 +235,12 @@
"libui_headers",
],
min_sdk_version: "29",
+ // TODO(b/214400477) to remove use of GraphicBuffer
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ "test_com.android.media.swcodec",
+ ],
afdo: true,
}
@@ -258,6 +264,11 @@
"libmath_headers",
],
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ "test_com.android.media.swcodec",
+ ],
}
// defaults to enable VALIDATE_REGIONS traces
diff --git a/libs/ui/include/ui/StretchEffect.h b/libs/ui/include/ui/StretchEffect.h
index cf08acb..123b275 100644
--- a/libs/ui/include/ui/StretchEffect.h
+++ b/libs/ui/include/ui/StretchEffect.h
@@ -44,6 +44,8 @@
mappedChildBounds == other.mappedChildBounds;
}
+ bool operator!=(const StretchEffect& other) const { return !(*this == other); }
+
static bool isZero(float value) {
constexpr float NON_ZERO_EPSILON = 0.001f;
return fabsf(value) <= NON_ZERO_EPSILON;
diff --git a/services/gpuservice/gpumem/Android.bp b/services/gpuservice/gpumem/Android.bp
index 24087ac..d0ea856 100644
--- a/services/gpuservice/gpumem/Android.bp
+++ b/services/gpuservice/gpumem/Android.bp
@@ -26,19 +26,17 @@
srcs: [
"GpuMem.cpp",
],
+ header_libs: ["bpf_headers"],
shared_libs: [
"libbase",
"libbpf_bcc",
- "libbpf_android",
"libcutils",
"liblog",
"libutils",
],
export_include_dirs: ["include"],
- export_shared_lib_headers: [
- "libbase",
- "libbpf_android",
- ],
+ export_header_lib_headers: ["bpf_headers"],
+ export_shared_lib_headers: ["libbase"],
cppflags: [
"-Wall",
"-Werror",
diff --git a/services/gpuservice/gpuwork/Android.bp b/services/gpuservice/gpuwork/Android.bp
index 89b31a6..a9a59bc 100644
--- a/services/gpuservice/gpuwork/Android.bp
+++ b/services/gpuservice/gpuwork/Android.bp
@@ -22,13 +22,13 @@
"GpuWork.cpp",
],
header_libs: [
+ "bpf_headers",
"gpu_work_structs",
],
shared_libs: [
"libbase",
"libbinder",
"libbpf_bcc",
- "libbpf_android",
"libcutils",
"liblog",
"libstatslog",
@@ -43,7 +43,6 @@
],
export_shared_lib_headers: [
"libbase",
- "libbpf_android",
"libstatspull",
],
cppflags: [
diff --git a/services/gpuservice/gpuwork/GpuWork.cpp b/services/gpuservice/gpuwork/GpuWork.cpp
index e7b1cd4..67ce9f2 100644
--- a/services/gpuservice/gpuwork/GpuWork.cpp
+++ b/services/gpuservice/gpuwork/GpuWork.cpp
@@ -24,7 +24,6 @@
#include <binder/PermissionCache.h>
#include <bpf/WaitForProgsLoaded.h>
#include <libbpf.h>
-#include <libbpf_android.h>
#include <log/log.h>
#include <random>
#include <stats_event.h>
diff --git a/services/gpuservice/tests/unittests/Android.bp b/services/gpuservice/tests/unittests/Android.bp
index 5b69f96..4fb0d2e 100644
--- a/services/gpuservice/tests/unittests/Android.bp
+++ b/services/gpuservice/tests/unittests/Android.bp
@@ -32,10 +32,10 @@
"GpuMemTracerTest.cpp",
"GpuStatsTest.cpp",
],
+ header_libs: ["bpf_headers"],
shared_libs: [
"libbase",
"libbpf_bcc",
- "libbpf_android",
"libcutils",
"libgfxstats",
"libgpumem",
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 22a69e5..ed9bfd2 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -22,6 +22,10 @@
default_applicable_licenses: ["frameworks_native_license"],
}
+inputflinger_tidy_checks = [
+ "android-*",
+]
+
cc_defaults {
name: "inputflinger_defaults",
cpp_std: "c++20",
@@ -38,6 +42,11 @@
sanitize: {
misc_undefined: ["bounds"],
},
+ tidy: true,
+ tidy_checks: [
+ "-*", // Disable all checks not explicitly enabled for now
+ ] + inputflinger_tidy_checks,
+ tidy_checks_as_errors: inputflinger_tidy_checks,
}
/////////////////////////////////////////////////
@@ -48,7 +57,7 @@
name: "libinputflinger_sources",
srcs: [
"InputClassifier.cpp",
- "InputClassifierConverter.cpp",
+ "InputCommonConverter.cpp",
"UnwantedInteractionBlocker.cpp",
"InputManager.cpp",
],
@@ -58,9 +67,10 @@
name: "libinputflinger_defaults",
srcs: [":libinputflinger_sources"],
shared_libs: [
- "android.hardware.input.classifier@1.0",
+ "android.hardware.input.processor-V1-ndk",
"libbase",
"libbinder",
+ "libbinder_ndk",
"libchrome",
"libcrypto",
"libcutils",
diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp
index 6c4b11e..3ea0986 100644
--- a/services/inputflinger/InputClassifier.cpp
+++ b/services/inputflinger/InputClassifier.cpp
@@ -17,13 +17,15 @@
#define LOG_TAG "InputClassifier"
#include "InputClassifier.h"
-#include "InputClassifierConverter.h"
+#include "InputCommonConverter.h"
-#include <algorithm>
#include <android-base/stringprintf.h>
-#include <cmath>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
#include <inttypes.h>
#include <log/log.h>
+#include <algorithm>
+#include <cmath>
#if defined(__linux__)
#include <pthread.h>
#endif
@@ -36,10 +38,9 @@
#define INDENT5 " "
using android::base::StringPrintf;
-using android::hardware::hidl_bitfield;
-using android::hardware::hidl_vec;
-using android::hardware::Return;
-using namespace android::hardware::input;
+using namespace std::chrono_literals;
+using namespace ::aidl::android::hardware::input;
+using aidl::android::hardware::input::processor::IInputProcessor;
namespace android {
@@ -55,13 +56,13 @@
return it->second;
}
-static MotionClassification getMotionClassification(common::V1_0::Classification classification) {
+static MotionClassification getMotionClassification(common::Classification classification) {
static_assert(MotionClassification::NONE ==
- static_cast<MotionClassification>(common::V1_0::Classification::NONE));
+ static_cast<MotionClassification>(common::Classification::NONE));
static_assert(MotionClassification::AMBIGUOUS_GESTURE ==
- static_cast<MotionClassification>(common::V1_0::Classification::AMBIGUOUS_GESTURE));
+ static_cast<MotionClassification>(common::Classification::AMBIGUOUS_GESTURE));
static_assert(MotionClassification::DEEP_PRESS ==
- static_cast<MotionClassification>(common::V1_0::Classification::DEEP_PRESS));
+ static_cast<MotionClassification>(common::Classification::DEEP_PRESS));
return static_cast<MotionClassification>(classification);
}
@@ -70,6 +71,56 @@
isFromSource(args.source, AINPUT_SOURCE_TOUCHSCREEN);
}
+static void setCurrentThreadName(const char* name) {
+#if defined(__linux__)
+ // Set the thread name for debugging
+ pthread_setname_np(pthread_self(), name);
+#else
+ (void*)(name); // prevent unused variable warning
+#endif
+}
+
+static std::shared_ptr<IInputProcessor> getService() {
+ const std::string aidl_instance_name = std::string(IInputProcessor::descriptor) + "/default";
+
+ if (!AServiceManager_isDeclared(aidl_instance_name.c_str())) {
+ ALOGI("HAL %s is not declared", aidl_instance_name.c_str());
+ return nullptr;
+ }
+
+ ndk::SpAIBinder binder(AServiceManager_waitForService(aidl_instance_name.c_str()));
+ return IInputProcessor::fromBinder(binder);
+}
+
+// Temporarily releases a held mutex for the lifetime of the instance.
+// Named to match std::scoped_lock
+class scoped_unlock {
+public:
+ explicit scoped_unlock(std::mutex& mutex) : mMutex(mutex) { mMutex.unlock(); }
+ ~scoped_unlock() { mMutex.lock(); }
+
+private:
+ std::mutex& mMutex;
+};
+
+// --- ScopedDeathRecipient ---
+ScopedDeathRecipient::ScopedDeathRecipient(AIBinder_DeathRecipient_onBinderDied onBinderDied,
+ void* cookie)
+ : mCookie(cookie) {
+ mRecipient = AIBinder_DeathRecipient_new(onBinderDied);
+}
+
+void ScopedDeathRecipient::linkToDeath(AIBinder* binder) {
+ binder_status_t linked = AIBinder_linkToDeath(binder, mRecipient, mCookie);
+ if (linked != STATUS_OK) {
+ ALOGE("Could not link death recipient to the HAL death");
+ }
+}
+
+ScopedDeathRecipient::~ScopedDeathRecipient() {
+ AIBinder_DeathRecipient_delete(mRecipient);
+}
+
// --- ClassifierEvent ---
ClassifierEvent::ClassifierEvent(std::unique_ptr<NotifyMotionArgs> args) :
@@ -118,9 +169,8 @@
// --- MotionClassifier ---
-MotionClassifier::MotionClassifier(
- sp<android::hardware::input::classifier::V1_0::IInputClassifier> service)
- : mEvents(MAX_EVENTS), mService(service) {
+MotionClassifier::MotionClassifier(std::shared_ptr<IInputProcessor> service)
+ : mEvents(MAX_EVENTS), mService(std::move(service)) {
// Under normal operation, we do not need to reset the HAL here. But in the case where system
// crashed, but HAL didn't, we may be connecting to an existing HAL process that might already
// have received events in the past. That means, that HAL could be in an inconsistent state
@@ -135,23 +185,10 @@
}
std::unique_ptr<MotionClassifierInterface> MotionClassifier::create(
- sp<android::hardware::hidl_death_recipient> deathRecipient) {
- sp<android::hardware::input::classifier::V1_0::IInputClassifier> service =
- classifier::V1_0::IInputClassifier::getService();
- if (!service) {
- // Not really an error, maybe the device does not have this HAL,
- // but somehow the feature flag is flipped
- ALOGI("Could not obtain InputClassifier HAL");
- return nullptr;
- }
-
- const bool linked = service->linkToDeath(deathRecipient, 0 /* cookie */).withDefault(false);
- if (!linked) {
- ALOGE("Could not link death recipient to the HAL death");
- return nullptr;
- }
+ std::shared_ptr<IInputProcessor> service) {
+ LOG_ALWAYS_FATAL_IF(service == nullptr);
// Using 'new' to access a non-public constructor
- return std::unique_ptr<MotionClassifier>(new MotionClassifier(service));
+ return std::unique_ptr<MotionClassifier>(new MotionClassifier(std::move(service)));
}
MotionClassifier::~MotionClassifier() {
@@ -176,14 +213,12 @@
switch (event.type) {
case ClassifierEventType::MOTION: {
NotifyMotionArgs* motionArgs = static_cast<NotifyMotionArgs*>(event.args.get());
- common::V1_0::MotionEvent motionEvent =
- notifyMotionArgsToHalMotionEvent(*motionArgs);
- Return<common::V1_0::Classification> response = mService->classify(motionEvent);
- halResponseOk = response.isOk();
- if (halResponseOk) {
- common::V1_0::Classification halClassification = response;
+ common::MotionEvent motionEvent = notifyMotionArgsToHalMotionEvent(*motionArgs);
+ common::Classification classification;
+ ndk::ScopedAStatus response = mService->classify(motionEvent, &classification);
+ if (response.isOk()) {
updateClassification(motionArgs->deviceId, motionArgs->eventTime,
- getMotionClassification(halClassification));
+ getMotionClassification(classification));
}
break;
}
@@ -300,7 +335,8 @@
if (!mService) {
return "null";
}
- if (mService->ping().isOk()) {
+
+ if (AIBinder_ping(mService->asBinder().get()) == STATUS_OK) {
return "running";
}
return "not responding";
@@ -329,40 +365,53 @@
}
}
-// --- HalDeathRecipient
-
-InputClassifier::HalDeathRecipient::HalDeathRecipient(InputClassifier& parent) : mParent(parent) {}
-
-void InputClassifier::HalDeathRecipient::serviceDied(
- uint64_t cookie, const wp<android::hidl::base::V1_0::IBase>& who) {
- sp<android::hidl::base::V1_0::IBase> service = who.promote();
- if (service) {
- service->unlinkToDeath(this);
- }
- mParent.setMotionClassifier(nullptr);
-}
-
// --- InputClassifier ---
-InputClassifier::InputClassifier(InputListenerInterface& listener)
- : mListener(listener), mHalDeathRecipient(new HalDeathRecipient(*this)) {}
+InputClassifier::InputClassifier(InputListenerInterface& listener) : mListener(listener) {}
+
+void InputClassifier::onBinderDied(void* cookie) {
+ InputClassifier* classifier = static_cast<InputClassifier*>(cookie);
+ if (classifier == nullptr) {
+ LOG_ALWAYS_FATAL("Cookie is not valid");
+ return;
+ }
+ classifier->setMotionClassifierEnabled(false);
+}
void InputClassifier::setMotionClassifierEnabled(bool enabled) {
+ std::scoped_lock lock(mLock);
if (enabled) {
ALOGI("Enabling motion classifier");
- if (mInitializeMotionClassifierThread.joinable()) {
- mInitializeMotionClassifierThread.join();
+ if (mInitializeMotionClassifier.valid()) {
+ scoped_unlock unlock(mLock);
+ std::future_status status = mInitializeMotionClassifier.wait_for(5s);
+ if (status != std::future_status::ready) {
+ /**
+ * We don't have a better option here than to crash. We can't stop the thread,
+ * and we can't continue because 'mInitializeMotionClassifier' will block in its
+ * destructor.
+ */
+ LOG_ALWAYS_FATAL("The thread to load IInputClassifier is stuck!");
+ }
}
- mInitializeMotionClassifierThread = std::thread(
- [this] { setMotionClassifier(MotionClassifier::create(mHalDeathRecipient)); });
-#if defined(__linux__)
- // Set the thread name for debugging
- pthread_setname_np(mInitializeMotionClassifierThread.native_handle(),
- "Create MotionClassifier");
-#endif
+ mInitializeMotionClassifier = std::async(std::launch::async, [this] {
+ setCurrentThreadName("Create MotionClassifier");
+ std::shared_ptr<IInputProcessor> service = getService();
+ if (service == nullptr) {
+ // Keep the MotionClassifier null, no service was found
+ return;
+ }
+ { // acquire lock
+ std::scoped_lock threadLock(mLock);
+ mHalDeathRecipient =
+ std::make_unique<ScopedDeathRecipient>(onBinderDied, this /*cookie*/);
+ mHalDeathRecipient->linkToDeath(service->asBinder().get());
+ setMotionClassifierLocked(MotionClassifier::create(std::move(service)));
+ } // release lock
+ });
} else {
ALOGI("Disabling motion classifier");
- setMotionClassifier(nullptr);
+ setMotionClassifierLocked(nullptr);
}
}
@@ -419,9 +468,13 @@
mListener.notifyPointerCaptureChanged(args);
}
-void InputClassifier::setMotionClassifier(
- std::unique_ptr<MotionClassifierInterface> motionClassifier) {
- std::scoped_lock lock(mLock);
+void InputClassifier::setMotionClassifierLocked(
+ std::unique_ptr<MotionClassifierInterface> motionClassifier) REQUIRES(mLock) {
+ if (motionClassifier == nullptr) {
+ // Destroy the ScopedDeathRecipient object, which will cause it to unlinkToDeath.
+ // We can't call 'unlink' here because we don't have the binder handle.
+ mHalDeathRecipient = nullptr;
+ }
mMotionClassifier = std::move(motionClassifier);
}
@@ -438,9 +491,6 @@
}
InputClassifier::~InputClassifier() {
- if (mInitializeMotionClassifierThread.joinable()) {
- mInitializeMotionClassifierThread.join();
- }
}
} // namespace android
diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h
index deeae7c..e2a0bc2 100644
--- a/services/inputflinger/InputClassifier.h
+++ b/services/inputflinger/InputClassifier.h
@@ -18,13 +18,13 @@
#define _UI_INPUT_CLASSIFIER_H
#include <android-base/thread_annotations.h>
+#include <future>
#include <thread>
#include <unordered_map>
+#include <aidl/android/hardware/input/processor/IInputProcessor.h>
#include "BlockingQueue.h"
#include "InputListener.h"
-#include <android/hardware/input/classifier/1.0/IInputClassifier.h>
-
namespace android {
enum class ClassifierEventType : uint8_t {
@@ -102,6 +102,19 @@
// --- Implementations ---
+class ScopedDeathRecipient {
+public:
+ explicit ScopedDeathRecipient(AIBinder_DeathRecipient_onBinderDied onBinderDied, void* cookie);
+ ScopedDeathRecipient(const ScopedDeathRecipient&) = delete;
+ ScopedDeathRecipient& operator=(ScopedDeathRecipient const&) = delete;
+ void linkToDeath(AIBinder* binder);
+ ~ScopedDeathRecipient();
+
+private:
+ AIBinder_DeathRecipient* mRecipient;
+ void* mCookie;
+};
+
/**
* Implementation of MotionClassifierInterface that calls the InputClassifier HAL
* in order to determine the classification for the current gesture.
@@ -121,7 +134,7 @@
* This function should be called asynchronously, because getService takes a long time.
*/
static std::unique_ptr<MotionClassifierInterface> create(
- sp<android::hardware::hidl_death_recipient> deathRecipient);
+ std::shared_ptr<aidl::android::hardware::input::processor::IInputProcessor> service);
~MotionClassifier();
@@ -143,7 +156,7 @@
private:
friend class MotionClassifierTest; // to create MotionClassifier with a test HAL implementation
explicit MotionClassifier(
- sp<android::hardware::input::classifier::V1_0::IInputClassifier> service);
+ std::shared_ptr<aidl::android::hardware::input::processor::IInputProcessor> service);
// The events that need to be sent to the HAL.
BlockingQueue<ClassifierEvent> mEvents;
@@ -162,14 +175,14 @@
*/
void processEvents();
/**
- * Access to the InputClassifier HAL. May be null if init() hasn't completed yet.
+ * Access to the InputProcessor HAL. May be null if init() hasn't completed yet.
* When init() successfully completes, mService is guaranteed to remain non-null and to not
* change its value until MotionClassifier is destroyed.
* This variable is *not* guarded by mLock in the InputClassifier thread, because
* that thread knows exactly when this variable is initialized.
* When accessed in any other thread, mService is checked for nullness with a lock.
*/
- sp<android::hardware::input::classifier::V1_0::IInputClassifier> mService;
+ std::shared_ptr<aidl::android::hardware::input::processor::IInputProcessor> mService;
std::mutex mLock;
/**
* Per-device input classifications. Should only be accessed using the
@@ -224,21 +237,21 @@
public:
explicit InputClassifier(InputListenerInterface& listener);
- virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
- virtual void notifyKey(const NotifyKeyArgs* args) override;
- virtual void notifyMotion(const NotifyMotionArgs* args) override;
- virtual void notifySwitch(const NotifySwitchArgs* args) override;
- virtual void notifySensor(const NotifySensorArgs* args) override;
- virtual void notifyVibratorState(const NotifyVibratorStateArgs* args) override;
- virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
+ void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
+ void notifyKey(const NotifyKeyArgs* args) override;
+ void notifyMotion(const NotifyMotionArgs* args) override;
+ void notifySwitch(const NotifySwitchArgs* args) override;
+ void notifySensor(const NotifySensorArgs* args) override;
+ void notifyVibratorState(const NotifyVibratorStateArgs* args) override;
+ void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
- virtual void dump(std::string& dump) override;
+ void dump(std::string& dump) override;
~InputClassifier();
// Called from InputManager
- virtual void setMotionClassifierEnabled(bool enabled) override;
+ void setMotionClassifierEnabled(bool enabled) override;
private:
// Protect access to mMotionClassifier, since it may become null via a hidl callback
@@ -247,7 +260,8 @@
InputListenerInterface& mListener;
std::unique_ptr<MotionClassifierInterface> mMotionClassifier GUARDED_BY(mLock);
- std::thread mInitializeMotionClassifierThread;
+ std::future<void> mInitializeMotionClassifier GUARDED_BY(mLock);
+
/**
* Set the value of mMotionClassifier.
* This is called from 2 different threads:
@@ -255,25 +269,12 @@
* 2) A binder thread of the HalDeathRecipient, which is created when HAL dies. This would cause
* mMotionClassifier to become nullptr.
*/
- void setMotionClassifier(std::unique_ptr<MotionClassifierInterface> motionClassifier);
+ void setMotionClassifierLocked(std::unique_ptr<MotionClassifierInterface> motionClassifier)
+ REQUIRES(mLock);
- /**
- * The deathRecipient will call setMotionClassifier(null) when the HAL dies.
- */
- class HalDeathRecipient : public android::hardware::hidl_death_recipient {
- public:
- explicit HalDeathRecipient(InputClassifier& parent);
- virtual void serviceDied(uint64_t cookie,
- const wp<android::hidl::base::V1_0::IBase>& who) override;
+ static void onBinderDied(void* cookie);
- private:
- InputClassifier& mParent;
- };
- // We retain a reference to death recipient, because the death recipient will be calling
- // ~MotionClassifier if the HAL dies.
- // If we don't retain a reference, and MotionClassifier is the only owner of the death
- // recipient, the serviceDied call will cause death recipient to call its own destructor.
- sp<HalDeathRecipient> mHalDeathRecipient;
+ std::unique_ptr<ScopedDeathRecipient> mHalDeathRecipient GUARDED_BY(mLock);
};
} // namespace android
diff --git a/services/inputflinger/InputClassifierConverter.cpp b/services/inputflinger/InputClassifierConverter.cpp
deleted file mode 100644
index b58a188..0000000
--- a/services/inputflinger/InputClassifierConverter.cpp
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- * Copyright (C) 2019 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 "InputClassifierConverter.h"
-
-using android::hardware::hidl_bitfield;
-using namespace android::hardware::input;
-
-namespace android {
-
-static common::V1_0::Source getSource(uint32_t source) {
- static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_UNKNOWN) ==
- common::V1_0::Source::UNKNOWN, "SOURCE_UNKNOWN mismatch");
- static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_KEYBOARD) ==
- common::V1_0::Source::KEYBOARD, "SOURCE_KEYBOARD mismatch");
- static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_DPAD) ==
- common::V1_0::Source::DPAD, "SOURCE_DPAD mismatch");
- static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_GAMEPAD) ==
- common::V1_0::Source::GAMEPAD, "SOURCE_GAMEPAD mismatch");
- static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_TOUCHSCREEN) ==
- common::V1_0::Source::TOUCHSCREEN, "SOURCE_TOUCHSCREEN mismatch");
- static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_MOUSE) ==
- common::V1_0::Source::MOUSE, "SOURCE_MOUSE mismatch");
- static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_STYLUS) ==
- common::V1_0::Source::STYLUS, "SOURCE_STYLUS mismatch");
- static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_BLUETOOTH_STYLUS) ==
- common::V1_0::Source::BLUETOOTH_STYLUS, "SOURCE_BLUETOOTH_STYLUS mismatch");
- static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_TRACKBALL) ==
- common::V1_0::Source::TRACKBALL, "SOURCE_TRACKBALL mismatch");
- static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_MOUSE_RELATIVE) ==
- common::V1_0::Source::MOUSE_RELATIVE, "SOURCE_MOUSE_RELATIVE mismatch");
- static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_TOUCHPAD) ==
- common::V1_0::Source::TOUCHPAD, "SOURCE_TOUCHPAD mismatch");
- static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_TOUCH_NAVIGATION) ==
- common::V1_0::Source::TOUCH_NAVIGATION, "SOURCE_TOUCH_NAVIGATION mismatch");
- static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_JOYSTICK) ==
- common::V1_0::Source::JOYSTICK, "SOURCE_JOYSTICK mismatch");
- static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_ROTARY_ENCODER) ==
- common::V1_0::Source::ROTARY_ENCODER, "SOURCE_ROTARY_ENCODER mismatch");
- static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_ANY) ==
- common::V1_0::Source::ANY, "SOURCE_ANY mismatch");
- return static_cast<common::V1_0::Source>(source);
-}
-
-static common::V1_0::Action getAction(int32_t actionMasked) {
- static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_DOWN) ==
- common::V1_0::Action::DOWN, "ACTION_DOWN mismatch");
- static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_UP) ==
- common::V1_0::Action::UP, "ACTION_UP mismatch");
- static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_MOVE) ==
- common::V1_0::Action::MOVE, "ACTION_MOVE mismatch");
- static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_CANCEL) ==
- common::V1_0::Action::CANCEL, "ACTION_CANCEL mismatch");
- static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_OUTSIDE) ==
- common::V1_0::Action::OUTSIDE, "ACTION_OUTSIDE mismatch");
- static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_POINTER_DOWN) ==
- common::V1_0::Action::POINTER_DOWN, "ACTION_POINTER_DOWN mismatch");
- static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_POINTER_UP) ==
- common::V1_0::Action::POINTER_UP, "ACTION_POINTER_UP mismatch");
- static_assert(static_cast<common::V1_0::Action>( AMOTION_EVENT_ACTION_HOVER_MOVE) ==
- common::V1_0::Action::HOVER_MOVE, "ACTION_HOVER_MOVE mismatch");
- static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_SCROLL) ==
- common::V1_0::Action::SCROLL, "ACTION_SCROLL mismatch");
- static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_HOVER_ENTER) ==
- common::V1_0::Action::HOVER_ENTER, "ACTION_HOVER_ENTER mismatch");
- static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_HOVER_EXIT) ==
- common::V1_0::Action::HOVER_EXIT, "ACTION_HOVER_EXIT mismatch");
- static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_BUTTON_PRESS) ==
- common::V1_0::Action::BUTTON_PRESS, "ACTION_BUTTON_PRESS mismatch");
- static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_BUTTON_RELEASE) ==
- common::V1_0::Action::BUTTON_RELEASE, "ACTION_BUTTON_RELEASE mismatch");
- return static_cast<common::V1_0::Action>(actionMasked);
-}
-
-static common::V1_0::Button getActionButton(int32_t actionButton) {
- static_assert(static_cast<common::V1_0::Button>(0) ==
- common::V1_0::Button::NONE, "BUTTON_NONE mismatch");
- static_assert(static_cast<common::V1_0::Button>(AMOTION_EVENT_BUTTON_PRIMARY) ==
- common::V1_0::Button::PRIMARY, "BUTTON_PRIMARY mismatch");
- static_assert(static_cast<common::V1_0::Button>(AMOTION_EVENT_BUTTON_SECONDARY) ==
- common::V1_0::Button::SECONDARY, "BUTTON_SECONDARY mismatch");
- static_assert(static_cast<common::V1_0::Button>(AMOTION_EVENT_BUTTON_TERTIARY) ==
- common::V1_0::Button::TERTIARY, "BUTTON_TERTIARY mismatch");
- static_assert(static_cast<common::V1_0::Button>(AMOTION_EVENT_BUTTON_BACK) ==
- common::V1_0::Button::BACK, "BUTTON_BACK mismatch");
- static_assert(static_cast<common::V1_0::Button>(AMOTION_EVENT_BUTTON_FORWARD) ==
- common::V1_0::Button::FORWARD, "BUTTON_FORWARD mismatch");
- static_assert(static_cast<common::V1_0::Button>(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) ==
- common::V1_0::Button::STYLUS_PRIMARY, "BUTTON_STYLUS_PRIMARY mismatch");
- static_assert(static_cast<common::V1_0::Button>(AMOTION_EVENT_BUTTON_STYLUS_SECONDARY) ==
- common::V1_0::Button::STYLUS_SECONDARY, "BUTTON_STYLUS_SECONDARY mismatch");
- return static_cast<common::V1_0::Button>(actionButton);
-}
-
-static hidl_bitfield<common::V1_0::Flag> getFlags(int32_t flags) {
- static_assert(static_cast<common::V1_0::Flag>(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED) ==
- common::V1_0::Flag::WINDOW_IS_OBSCURED);
- static_assert(static_cast<common::V1_0::Flag>(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE) ==
- common::V1_0::Flag::IS_GENERATED_GESTURE);
- static_assert(static_cast<common::V1_0::Flag>(AMOTION_EVENT_FLAG_TAINTED) ==
- common::V1_0::Flag::TAINTED);
- return static_cast<hidl_bitfield<common::V1_0::Flag>>(flags);
-}
-
-static hidl_bitfield<common::V1_0::PolicyFlag> getPolicyFlags(int32_t flags) {
- static_assert(static_cast<common::V1_0::PolicyFlag>(POLICY_FLAG_WAKE) ==
- common::V1_0::PolicyFlag::WAKE);
- static_assert(static_cast<common::V1_0::PolicyFlag>(POLICY_FLAG_VIRTUAL) ==
- common::V1_0::PolicyFlag::VIRTUAL);
- static_assert(static_cast<common::V1_0::PolicyFlag>(POLICY_FLAG_FUNCTION) ==
- common::V1_0::PolicyFlag::FUNCTION);
- static_assert(static_cast<common::V1_0::PolicyFlag>(POLICY_FLAG_GESTURE) ==
- common::V1_0::PolicyFlag::GESTURE);
- static_assert(static_cast<common::V1_0::PolicyFlag>(POLICY_FLAG_INJECTED) ==
- common::V1_0::PolicyFlag::INJECTED);
- static_assert(static_cast<common::V1_0::PolicyFlag>(POLICY_FLAG_TRUSTED) ==
- common::V1_0::PolicyFlag::TRUSTED);
- static_assert(static_cast<common::V1_0::PolicyFlag>(POLICY_FLAG_FILTERED) ==
- common::V1_0::PolicyFlag::FILTERED);
- static_assert(static_cast<common::V1_0::PolicyFlag>(POLICY_FLAG_DISABLE_KEY_REPEAT) ==
- common::V1_0::PolicyFlag::DISABLE_KEY_REPEAT);
- static_assert(static_cast<common::V1_0::PolicyFlag>(POLICY_FLAG_INTERACTIVE) ==
- common::V1_0::PolicyFlag::INTERACTIVE);
- static_assert(static_cast<common::V1_0::PolicyFlag>(POLICY_FLAG_PASS_TO_USER) ==
- common::V1_0::PolicyFlag::PASS_TO_USER);
- return static_cast<hidl_bitfield<common::V1_0::PolicyFlag>>(flags);
-}
-
-static hidl_bitfield<common::V1_0::EdgeFlag> getEdgeFlags(int32_t flags) {
- static_assert(static_cast<common::V1_0::EdgeFlag>(AMOTION_EVENT_EDGE_FLAG_NONE) ==
- common::V1_0::EdgeFlag::NONE);
- static_assert(static_cast<common::V1_0::EdgeFlag>(AMOTION_EVENT_EDGE_FLAG_TOP) ==
- common::V1_0::EdgeFlag::TOP);
- static_assert(static_cast<common::V1_0::EdgeFlag>(AMOTION_EVENT_EDGE_FLAG_BOTTOM) ==
- common::V1_0::EdgeFlag::BOTTOM);
- static_assert(static_cast<common::V1_0::EdgeFlag>(AMOTION_EVENT_EDGE_FLAG_LEFT) ==
- common::V1_0::EdgeFlag::LEFT);
- static_assert(static_cast<common::V1_0::EdgeFlag>(AMOTION_EVENT_EDGE_FLAG_RIGHT) ==
- common::V1_0::EdgeFlag::RIGHT);
- return static_cast<hidl_bitfield<common::V1_0::EdgeFlag>>(flags);
-}
-
-static hidl_bitfield<common::V1_0::Meta> getMetastate(int32_t state) {
- static_assert(static_cast<common::V1_0::Meta>(AMETA_NONE) ==
- common::V1_0::Meta::NONE);
- static_assert(static_cast<common::V1_0::Meta>(AMETA_ALT_ON) ==
- common::V1_0::Meta::ALT_ON);
- static_assert(static_cast<common::V1_0::Meta>(AMETA_ALT_LEFT_ON) ==
- common::V1_0::Meta::ALT_LEFT_ON);
- static_assert(static_cast<common::V1_0::Meta>(AMETA_ALT_RIGHT_ON) ==
- common::V1_0::Meta::ALT_RIGHT_ON);
- static_assert(static_cast<common::V1_0::Meta>(AMETA_SHIFT_ON) ==
- common::V1_0::Meta::SHIFT_ON);
- static_assert(static_cast<common::V1_0::Meta>(AMETA_SHIFT_LEFT_ON) ==
- common::V1_0::Meta::SHIFT_LEFT_ON);
- static_assert(static_cast<common::V1_0::Meta>(AMETA_SHIFT_RIGHT_ON) ==
- common::V1_0::Meta::SHIFT_RIGHT_ON);
- static_assert(static_cast<common::V1_0::Meta>(AMETA_SYM_ON) ==
- common::V1_0::Meta::SYM_ON);
- static_assert(static_cast<common::V1_0::Meta>(AMETA_FUNCTION_ON) ==
- common::V1_0::Meta::FUNCTION_ON);
- static_assert(static_cast<common::V1_0::Meta>(AMETA_CTRL_ON) ==
- common::V1_0::Meta::CTRL_ON);
- static_assert(static_cast<common::V1_0::Meta>(AMETA_CTRL_LEFT_ON) ==
- common::V1_0::Meta::CTRL_LEFT_ON);
- static_assert(static_cast<common::V1_0::Meta>(AMETA_CTRL_RIGHT_ON) ==
- common::V1_0::Meta::CTRL_RIGHT_ON);
- static_assert(static_cast<common::V1_0::Meta>(AMETA_META_ON) ==
- common::V1_0::Meta::META_ON);
- static_assert(static_cast<common::V1_0::Meta>(AMETA_META_LEFT_ON) ==
- common::V1_0::Meta::META_LEFT_ON);
- static_assert(static_cast<common::V1_0::Meta>(AMETA_META_RIGHT_ON) ==
- common::V1_0::Meta::META_RIGHT_ON);
- static_assert(static_cast<common::V1_0::Meta>(AMETA_CAPS_LOCK_ON) ==
- common::V1_0::Meta::CAPS_LOCK_ON);
- static_assert(static_cast<common::V1_0::Meta>(AMETA_NUM_LOCK_ON) ==
- common::V1_0::Meta::NUM_LOCK_ON);
- static_assert(static_cast<common::V1_0::Meta>(AMETA_SCROLL_LOCK_ON) ==
- common::V1_0::Meta::SCROLL_LOCK_ON);
- return static_cast<hidl_bitfield<common::V1_0::Meta>>(state);
-}
-
-static hidl_bitfield<common::V1_0::Button> getButtonState(int32_t buttonState) {
- // No need for static_assert here.
- // The button values have already been asserted in getActionButton(..) above
- return static_cast<hidl_bitfield<common::V1_0::Button>>(buttonState);
-}
-
-static common::V1_0::ToolType getToolType(int32_t toolType) {
- static_assert(static_cast<common::V1_0::ToolType>(AMOTION_EVENT_TOOL_TYPE_UNKNOWN) ==
- common::V1_0::ToolType::UNKNOWN);
- static_assert(static_cast<common::V1_0::ToolType>(AMOTION_EVENT_TOOL_TYPE_FINGER) ==
- common::V1_0::ToolType::FINGER);
- static_assert(static_cast<common::V1_0::ToolType>(AMOTION_EVENT_TOOL_TYPE_STYLUS) ==
- common::V1_0::ToolType::STYLUS);
- static_assert(static_cast<common::V1_0::ToolType>(AMOTION_EVENT_TOOL_TYPE_MOUSE) ==
- common::V1_0::ToolType::MOUSE);
- static_assert(static_cast<common::V1_0::ToolType>(AMOTION_EVENT_TOOL_TYPE_ERASER) ==
- common::V1_0::ToolType::ERASER);
- return static_cast<common::V1_0::ToolType>(toolType);
-}
-
-// MotionEvent axes asserts
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_X) ==
- common::V1_0::Axis::X);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_Y) ==
- common::V1_0::Axis::Y);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_PRESSURE) ==
- common::V1_0::Axis::PRESSURE);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_SIZE) ==
- common::V1_0::Axis::SIZE);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_TOUCH_MAJOR) ==
- common::V1_0::Axis::TOUCH_MAJOR);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_TOUCH_MINOR) ==
- common::V1_0::Axis::TOUCH_MINOR);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_TOOL_MAJOR) ==
- common::V1_0::Axis::TOOL_MAJOR);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_TOOL_MINOR) ==
- common::V1_0::Axis::TOOL_MINOR);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_ORIENTATION) ==
- common::V1_0::Axis::ORIENTATION);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_VSCROLL) ==
- common::V1_0::Axis::VSCROLL);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_HSCROLL) ==
- common::V1_0::Axis::HSCROLL);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_Z) ==
- common::V1_0::Axis::Z);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_RX) ==
- common::V1_0::Axis::RX);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_RY) ==
- common::V1_0::Axis::RY);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_RZ) ==
- common::V1_0::Axis::RZ);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_HAT_X) ==
- common::V1_0::Axis::HAT_X);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_HAT_Y) ==
- common::V1_0::Axis::HAT_Y);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_LTRIGGER) ==
- common::V1_0::Axis::LTRIGGER);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_RTRIGGER) ==
- common::V1_0::Axis::RTRIGGER);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_THROTTLE) ==
- common::V1_0::Axis::THROTTLE);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_RUDDER) ==
- common::V1_0::Axis::RUDDER);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_WHEEL) ==
- common::V1_0::Axis::WHEEL);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GAS) ==
- common::V1_0::Axis::GAS);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_BRAKE) ==
- common::V1_0::Axis::BRAKE);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_DISTANCE) ==
- common::V1_0::Axis::DISTANCE);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_TILT) ==
- common::V1_0::Axis::TILT);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_SCROLL) ==
- common::V1_0::Axis::SCROLL);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_RELATIVE_X) ==
- common::V1_0::Axis::RELATIVE_X);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_RELATIVE_Y) ==
- common::V1_0::Axis::RELATIVE_Y);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_1) ==
- common::V1_0::Axis::GENERIC_1);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_2) ==
- common::V1_0::Axis::GENERIC_2);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_3) ==
- common::V1_0::Axis::GENERIC_3);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_4) ==
- common::V1_0::Axis::GENERIC_4);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_5) ==
- common::V1_0::Axis::GENERIC_5);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_6) ==
- common::V1_0::Axis::GENERIC_6);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_7) ==
- common::V1_0::Axis::GENERIC_7);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_8) ==
- common::V1_0::Axis::GENERIC_8);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_9) ==
- common::V1_0::Axis::GENERIC_9);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_10) ==
- common::V1_0::Axis::GENERIC_10);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_11) ==
- common::V1_0::Axis::GENERIC_11);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_12) ==
- common::V1_0::Axis::GENERIC_12);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_13) ==
- common::V1_0::Axis::GENERIC_13);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_14) ==
- common::V1_0::Axis::GENERIC_14);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_15) ==
- common::V1_0::Axis::GENERIC_15);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_16) ==
- common::V1_0::Axis::GENERIC_16);
-
-static common::V1_0::VideoFrame getHalVideoFrame(const TouchVideoFrame& frame) {
- common::V1_0::VideoFrame out;
- out.width = frame.getWidth();
- out.height = frame.getHeight();
- out.data = frame.getData();
- struct timeval timestamp = frame.getTimestamp();
- out.timestamp = seconds_to_nanoseconds(timestamp.tv_sec) +
- microseconds_to_nanoseconds(timestamp.tv_usec);
- return out;
-}
-
-static std::vector<common::V1_0::VideoFrame> convertVideoFrames(
- const std::vector<TouchVideoFrame>& frames) {
- std::vector<common::V1_0::VideoFrame> out;
- for (const TouchVideoFrame& frame : frames) {
- out.push_back(getHalVideoFrame(frame));
- }
- return out;
-}
-
-static void getHidlPropertiesAndCoords(const NotifyMotionArgs& args,
- std::vector<common::V1_0::PointerProperties>* outPointerProperties,
- std::vector<common::V1_0::PointerCoords>* outPointerCoords) {
- outPointerProperties->reserve(args.pointerCount);
- outPointerCoords->reserve(args.pointerCount);
- for (size_t i = 0; i < args.pointerCount; i++) {
- common::V1_0::PointerProperties properties;
- properties.id = args.pointerProperties[i].id;
- properties.toolType = getToolType(args.pointerProperties[i].toolType);
- outPointerProperties->push_back(properties);
-
- common::V1_0::PointerCoords coords;
- // OK to copy bits because we have static_assert for pointerCoords axes
- coords.bits = args.pointerCoords[i].bits;
- coords.values = std::vector<float>(
- args.pointerCoords[i].values,
- args.pointerCoords[i].values + BitSet64::count(args.pointerCoords[i].bits));
- outPointerCoords->push_back(coords);
- }
-}
-
-common::V1_0::MotionEvent notifyMotionArgsToHalMotionEvent(const NotifyMotionArgs& args) {
- common::V1_0::MotionEvent event;
- event.deviceId = args.deviceId;
- event.source = getSource(args.source);
- event.displayId = args.displayId;
- event.downTime = args.downTime;
- event.eventTime = args.eventTime;
- event.deviceTimestamp = 0;
- event.action = getAction(args.action & AMOTION_EVENT_ACTION_MASK);
- event.actionIndex = MotionEvent::getActionIndex(args.action);
- event.actionButton = getActionButton(args.actionButton);
- event.flags = getFlags(args.flags);
- event.policyFlags = getPolicyFlags(args.policyFlags);
- event.edgeFlags = getEdgeFlags(args.edgeFlags);
- event.metaState = getMetastate(args.metaState);
- event.buttonState = getButtonState(args.buttonState);
- event.xPrecision = args.xPrecision;
- event.yPrecision = args.yPrecision;
-
- std::vector<common::V1_0::PointerProperties> pointerProperties;
- std::vector<common::V1_0::PointerCoords> pointerCoords;
- getHidlPropertiesAndCoords(args, /*out*/&pointerProperties, /*out*/&pointerCoords);
- event.pointerProperties = pointerProperties;
- event.pointerCoords = pointerCoords;
-
- event.frames = convertVideoFrames(args.videoFrames);
-
- return event;
-}
-
-} // namespace android
diff --git a/services/inputflinger/InputCommonConverter.cpp b/services/inputflinger/InputCommonConverter.cpp
new file mode 100644
index 0000000..8aee39f
--- /dev/null
+++ b/services/inputflinger/InputCommonConverter.cpp
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "InputCommonConverter.h"
+
+using namespace ::aidl::android::hardware::input;
+
+namespace android {
+
+static common::Source getSource(uint32_t source) {
+ static_assert(static_cast<common::Source>(AINPUT_SOURCE_UNKNOWN) == common::Source::UNKNOWN,
+ "SOURCE_UNKNOWN mismatch");
+ static_assert(static_cast<common::Source>(AINPUT_SOURCE_KEYBOARD) == common::Source::KEYBOARD,
+ "SOURCE_KEYBOARD mismatch");
+ static_assert(static_cast<common::Source>(AINPUT_SOURCE_DPAD) == common::Source::DPAD,
+ "SOURCE_DPAD mismatch");
+ static_assert(static_cast<common::Source>(AINPUT_SOURCE_GAMEPAD) == common::Source::GAMEPAD,
+ "SOURCE_GAMEPAD mismatch");
+ static_assert(static_cast<common::Source>(AINPUT_SOURCE_TOUCHSCREEN) ==
+ common::Source::TOUCHSCREEN,
+ "SOURCE_TOUCHSCREEN mismatch");
+ static_assert(static_cast<common::Source>(AINPUT_SOURCE_MOUSE) == common::Source::MOUSE,
+ "SOURCE_MOUSE mismatch");
+ static_assert(static_cast<common::Source>(AINPUT_SOURCE_STYLUS) == common::Source::STYLUS,
+ "SOURCE_STYLUS mismatch");
+ static_assert(static_cast<common::Source>(AINPUT_SOURCE_BLUETOOTH_STYLUS) ==
+ common::Source::BLUETOOTH_STYLUS,
+ "SOURCE_BLUETOOTH_STYLUS mismatch");
+ static_assert(static_cast<common::Source>(AINPUT_SOURCE_TRACKBALL) == common::Source::TRACKBALL,
+ "SOURCE_TRACKBALL mismatch");
+ static_assert(static_cast<common::Source>(AINPUT_SOURCE_MOUSE_RELATIVE) ==
+ common::Source::MOUSE_RELATIVE,
+ "SOURCE_MOUSE_RELATIVE mismatch");
+ static_assert(static_cast<common::Source>(AINPUT_SOURCE_TOUCHPAD) == common::Source::TOUCHPAD,
+ "SOURCE_TOUCHPAD mismatch");
+ static_assert(static_cast<common::Source>(AINPUT_SOURCE_TOUCH_NAVIGATION) ==
+ common::Source::TOUCH_NAVIGATION,
+ "SOURCE_TOUCH_NAVIGATION mismatch");
+ static_assert(static_cast<common::Source>(AINPUT_SOURCE_JOYSTICK) == common::Source::JOYSTICK,
+ "SOURCE_JOYSTICK mismatch");
+ static_assert(static_cast<common::Source>(AINPUT_SOURCE_ROTARY_ENCODER) ==
+ common::Source::ROTARY_ENCODER,
+ "SOURCE_ROTARY_ENCODER mismatch");
+ static_assert(static_cast<common::Source>(AINPUT_SOURCE_HDMI) == common::Source::HDMI);
+ static_assert(static_cast<common::Source>(AINPUT_SOURCE_SENSOR) == common::Source::SENSOR);
+ static_assert(static_cast<common::Source>(AINPUT_SOURCE_ANY) == common::Source::ANY,
+ "SOURCE_ANY mismatch");
+ return static_cast<common::Source>(source);
+}
+
+static common::Action getAction(int32_t actionMasked) {
+ static_assert(static_cast<common::Action>(AMOTION_EVENT_ACTION_DOWN) == common::Action::DOWN,
+ "ACTION_DOWN mismatch");
+ static_assert(static_cast<common::Action>(AMOTION_EVENT_ACTION_UP) == common::Action::UP,
+ "ACTION_UP mismatch");
+ static_assert(static_cast<common::Action>(AMOTION_EVENT_ACTION_MOVE) == common::Action::MOVE,
+ "ACTION_MOVE mismatch");
+ static_assert(static_cast<common::Action>(AMOTION_EVENT_ACTION_CANCEL) ==
+ common::Action::CANCEL,
+ "ACTION_CANCEL mismatch");
+ static_assert(static_cast<common::Action>(AMOTION_EVENT_ACTION_OUTSIDE) ==
+ common::Action::OUTSIDE,
+ "ACTION_OUTSIDE mismatch");
+ static_assert(static_cast<common::Action>(AMOTION_EVENT_ACTION_POINTER_DOWN) ==
+ common::Action::POINTER_DOWN,
+ "ACTION_POINTER_DOWN mismatch");
+ static_assert(static_cast<common::Action>(AMOTION_EVENT_ACTION_POINTER_UP) ==
+ common::Action::POINTER_UP,
+ "ACTION_POINTER_UP mismatch");
+ static_assert(static_cast<common::Action>(AMOTION_EVENT_ACTION_HOVER_MOVE) ==
+ common::Action::HOVER_MOVE,
+ "ACTION_HOVER_MOVE mismatch");
+ static_assert(static_cast<common::Action>(AMOTION_EVENT_ACTION_SCROLL) ==
+ common::Action::SCROLL,
+ "ACTION_SCROLL mismatch");
+ static_assert(static_cast<common::Action>(AMOTION_EVENT_ACTION_HOVER_ENTER) ==
+ common::Action::HOVER_ENTER,
+ "ACTION_HOVER_ENTER mismatch");
+ static_assert(static_cast<common::Action>(AMOTION_EVENT_ACTION_HOVER_EXIT) ==
+ common::Action::HOVER_EXIT,
+ "ACTION_HOVER_EXIT mismatch");
+ static_assert(static_cast<common::Action>(AMOTION_EVENT_ACTION_BUTTON_PRESS) ==
+ common::Action::BUTTON_PRESS,
+ "ACTION_BUTTON_PRESS mismatch");
+ static_assert(static_cast<common::Action>(AMOTION_EVENT_ACTION_BUTTON_RELEASE) ==
+ common::Action::BUTTON_RELEASE,
+ "ACTION_BUTTON_RELEASE mismatch");
+ return static_cast<common::Action>(actionMasked);
+}
+
+static common::Button getActionButton(int32_t actionButton) {
+ static_assert(static_cast<common::Button>(0) == common::Button::NONE, "BUTTON_NONE mismatch");
+ static_assert(static_cast<common::Button>(AMOTION_EVENT_BUTTON_PRIMARY) ==
+ common::Button::PRIMARY,
+ "BUTTON_PRIMARY mismatch");
+ static_assert(static_cast<common::Button>(AMOTION_EVENT_BUTTON_SECONDARY) ==
+ common::Button::SECONDARY,
+ "BUTTON_SECONDARY mismatch");
+ static_assert(static_cast<common::Button>(AMOTION_EVENT_BUTTON_TERTIARY) ==
+ common::Button::TERTIARY,
+ "BUTTON_TERTIARY mismatch");
+ static_assert(static_cast<common::Button>(AMOTION_EVENT_BUTTON_BACK) == common::Button::BACK,
+ "BUTTON_BACK mismatch");
+ static_assert(static_cast<common::Button>(AMOTION_EVENT_BUTTON_FORWARD) ==
+ common::Button::FORWARD,
+ "BUTTON_FORWARD mismatch");
+ static_assert(static_cast<common::Button>(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) ==
+ common::Button::STYLUS_PRIMARY,
+ "BUTTON_STYLUS_PRIMARY mismatch");
+ static_assert(static_cast<common::Button>(AMOTION_EVENT_BUTTON_STYLUS_SECONDARY) ==
+ common::Button::STYLUS_SECONDARY,
+ "BUTTON_STYLUS_SECONDARY mismatch");
+ return static_cast<common::Button>(actionButton);
+}
+
+static common::Flag getFlags(int32_t flags) {
+ static_assert(static_cast<common::Flag>(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED) ==
+ common::Flag::WINDOW_IS_OBSCURED);
+ static_assert(static_cast<common::Flag>(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE) ==
+ common::Flag::IS_GENERATED_GESTURE);
+ static_assert(static_cast<common::Flag>(AMOTION_EVENT_FLAG_TAINTED) == common::Flag::TAINTED);
+ return static_cast<common::Flag>(flags);
+}
+
+static common::PolicyFlag getPolicyFlags(int32_t flags) {
+ static_assert(static_cast<common::PolicyFlag>(POLICY_FLAG_WAKE) == common::PolicyFlag::WAKE);
+ static_assert(static_cast<common::PolicyFlag>(POLICY_FLAG_VIRTUAL) ==
+ common::PolicyFlag::VIRTUAL);
+ static_assert(static_cast<common::PolicyFlag>(POLICY_FLAG_FUNCTION) ==
+ common::PolicyFlag::FUNCTION);
+ static_assert(static_cast<common::PolicyFlag>(POLICY_FLAG_GESTURE) ==
+ common::PolicyFlag::GESTURE);
+ static_assert(static_cast<common::PolicyFlag>(POLICY_FLAG_INJECTED) ==
+ common::PolicyFlag::INJECTED);
+ static_assert(static_cast<common::PolicyFlag>(POLICY_FLAG_TRUSTED) ==
+ common::PolicyFlag::TRUSTED);
+ static_assert(static_cast<common::PolicyFlag>(POLICY_FLAG_FILTERED) ==
+ common::PolicyFlag::FILTERED);
+ static_assert(static_cast<common::PolicyFlag>(POLICY_FLAG_DISABLE_KEY_REPEAT) ==
+ common::PolicyFlag::DISABLE_KEY_REPEAT);
+ static_assert(static_cast<common::PolicyFlag>(POLICY_FLAG_INTERACTIVE) ==
+ common::PolicyFlag::INTERACTIVE);
+ static_assert(static_cast<common::PolicyFlag>(POLICY_FLAG_PASS_TO_USER) ==
+ common::PolicyFlag::PASS_TO_USER);
+ return static_cast<common::PolicyFlag>(flags);
+}
+
+static common::EdgeFlag getEdgeFlags(int32_t flags) {
+ static_assert(static_cast<common::EdgeFlag>(AMOTION_EVENT_EDGE_FLAG_NONE) ==
+ common::EdgeFlag::NONE);
+ static_assert(static_cast<common::EdgeFlag>(AMOTION_EVENT_EDGE_FLAG_TOP) ==
+ common::EdgeFlag::TOP);
+ static_assert(static_cast<common::EdgeFlag>(AMOTION_EVENT_EDGE_FLAG_BOTTOM) ==
+ common::EdgeFlag::BOTTOM);
+ static_assert(static_cast<common::EdgeFlag>(AMOTION_EVENT_EDGE_FLAG_LEFT) ==
+ common::EdgeFlag::LEFT);
+ static_assert(static_cast<common::EdgeFlag>(AMOTION_EVENT_EDGE_FLAG_RIGHT) ==
+ common::EdgeFlag::RIGHT);
+ return static_cast<common::EdgeFlag>(flags);
+}
+
+static common::Meta getMetastate(int32_t state) {
+ static_assert(static_cast<common::Meta>(AMETA_NONE) == common::Meta::NONE);
+ static_assert(static_cast<common::Meta>(AMETA_ALT_ON) == common::Meta::ALT_ON);
+ static_assert(static_cast<common::Meta>(AMETA_ALT_LEFT_ON) == common::Meta::ALT_LEFT_ON);
+ static_assert(static_cast<common::Meta>(AMETA_ALT_RIGHT_ON) == common::Meta::ALT_RIGHT_ON);
+ static_assert(static_cast<common::Meta>(AMETA_SHIFT_ON) == common::Meta::SHIFT_ON);
+ static_assert(static_cast<common::Meta>(AMETA_SHIFT_LEFT_ON) == common::Meta::SHIFT_LEFT_ON);
+ static_assert(static_cast<common::Meta>(AMETA_SHIFT_RIGHT_ON) == common::Meta::SHIFT_RIGHT_ON);
+ static_assert(static_cast<common::Meta>(AMETA_SYM_ON) == common::Meta::SYM_ON);
+ static_assert(static_cast<common::Meta>(AMETA_FUNCTION_ON) == common::Meta::FUNCTION_ON);
+ static_assert(static_cast<common::Meta>(AMETA_CTRL_ON) == common::Meta::CTRL_ON);
+ static_assert(static_cast<common::Meta>(AMETA_CTRL_LEFT_ON) == common::Meta::CTRL_LEFT_ON);
+ static_assert(static_cast<common::Meta>(AMETA_CTRL_RIGHT_ON) == common::Meta::CTRL_RIGHT_ON);
+ static_assert(static_cast<common::Meta>(AMETA_META_ON) == common::Meta::META_ON);
+ static_assert(static_cast<common::Meta>(AMETA_META_LEFT_ON) == common::Meta::META_LEFT_ON);
+ static_assert(static_cast<common::Meta>(AMETA_META_RIGHT_ON) == common::Meta::META_RIGHT_ON);
+ static_assert(static_cast<common::Meta>(AMETA_CAPS_LOCK_ON) == common::Meta::CAPS_LOCK_ON);
+ static_assert(static_cast<common::Meta>(AMETA_NUM_LOCK_ON) == common::Meta::NUM_LOCK_ON);
+ static_assert(static_cast<common::Meta>(AMETA_SCROLL_LOCK_ON) == common::Meta::SCROLL_LOCK_ON);
+ return static_cast<common::Meta>(state);
+}
+
+static common::Button getButtonState(int32_t buttonState) {
+ // No need for static_assert here.
+ // The button values have already been asserted in getActionButton(..) above
+ return static_cast<common::Button>(buttonState);
+}
+
+static common::ToolType getToolType(int32_t toolType) {
+ static_assert(static_cast<common::ToolType>(AMOTION_EVENT_TOOL_TYPE_UNKNOWN) ==
+ common::ToolType::UNKNOWN);
+ static_assert(static_cast<common::ToolType>(AMOTION_EVENT_TOOL_TYPE_FINGER) ==
+ common::ToolType::FINGER);
+ static_assert(static_cast<common::ToolType>(AMOTION_EVENT_TOOL_TYPE_STYLUS) ==
+ common::ToolType::STYLUS);
+ static_assert(static_cast<common::ToolType>(AMOTION_EVENT_TOOL_TYPE_MOUSE) ==
+ common::ToolType::MOUSE);
+ static_assert(static_cast<common::ToolType>(AMOTION_EVENT_TOOL_TYPE_ERASER) ==
+ common::ToolType::ERASER);
+ return static_cast<common::ToolType>(toolType);
+}
+
+// MotionEvent axes asserts
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_X) == common::Axis::X);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_Y) == common::Axis::Y);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_PRESSURE) == common::Axis::PRESSURE);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_SIZE) == common::Axis::SIZE);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_TOUCH_MAJOR) ==
+ common::Axis::TOUCH_MAJOR);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_TOUCH_MINOR) ==
+ common::Axis::TOUCH_MINOR);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_TOOL_MAJOR) == common::Axis::TOOL_MAJOR);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_TOOL_MINOR) == common::Axis::TOOL_MINOR);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_ORIENTATION) ==
+ common::Axis::ORIENTATION);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_VSCROLL) == common::Axis::VSCROLL);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_HSCROLL) == common::Axis::HSCROLL);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_Z) == common::Axis::Z);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_RX) == common::Axis::RX);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_RY) == common::Axis::RY);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_RZ) == common::Axis::RZ);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_HAT_X) == common::Axis::HAT_X);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_HAT_Y) == common::Axis::HAT_Y);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_LTRIGGER) == common::Axis::LTRIGGER);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_RTRIGGER) == common::Axis::RTRIGGER);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_THROTTLE) == common::Axis::THROTTLE);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_RUDDER) == common::Axis::RUDDER);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_WHEEL) == common::Axis::WHEEL);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GAS) == common::Axis::GAS);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_BRAKE) == common::Axis::BRAKE);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_DISTANCE) == common::Axis::DISTANCE);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_TILT) == common::Axis::TILT);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_SCROLL) == common::Axis::SCROLL);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_RELATIVE_X) == common::Axis::RELATIVE_X);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_RELATIVE_Y) == common::Axis::RELATIVE_Y);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_1) == common::Axis::GENERIC_1);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_2) == common::Axis::GENERIC_2);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_3) == common::Axis::GENERIC_3);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_4) == common::Axis::GENERIC_4);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_5) == common::Axis::GENERIC_5);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_6) == common::Axis::GENERIC_6);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_7) == common::Axis::GENERIC_7);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_8) == common::Axis::GENERIC_8);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_9) == common::Axis::GENERIC_9);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_10) == common::Axis::GENERIC_10);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_11) == common::Axis::GENERIC_11);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_12) == common::Axis::GENERIC_12);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_13) == common::Axis::GENERIC_13);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_14) == common::Axis::GENERIC_14);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_15) == common::Axis::GENERIC_15);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_16) == common::Axis::GENERIC_16);
+
+static common::VideoFrame getHalVideoFrame(const TouchVideoFrame& frame) {
+ common::VideoFrame out;
+ out.width = frame.getWidth();
+ out.height = frame.getHeight();
+ std::vector<char16_t> unsignedData(frame.getData().begin(), frame.getData().end());
+ out.data = unsignedData;
+ struct timeval timestamp = frame.getTimestamp();
+ out.timestamp = seconds_to_nanoseconds(timestamp.tv_sec) +
+ microseconds_to_nanoseconds(timestamp.tv_usec);
+ return out;
+}
+
+static std::vector<common::VideoFrame> convertVideoFrames(
+ const std::vector<TouchVideoFrame>& frames) {
+ std::vector<common::VideoFrame> out;
+ for (const TouchVideoFrame& frame : frames) {
+ out.push_back(getHalVideoFrame(frame));
+ }
+ return out;
+}
+
+static void getHalPropertiesAndCoords(const NotifyMotionArgs& args,
+ std::vector<common::PointerProperties>& outPointerProperties,
+ std::vector<common::PointerCoords>& outPointerCoords) {
+ outPointerProperties.reserve(args.pointerCount);
+ outPointerCoords.reserve(args.pointerCount);
+ for (size_t i = 0; i < args.pointerCount; i++) {
+ common::PointerProperties properties;
+ properties.id = args.pointerProperties[i].id;
+ properties.toolType = getToolType(args.pointerProperties[i].toolType);
+ outPointerProperties.push_back(properties);
+
+ common::PointerCoords coords;
+ // OK to copy bits because we have static_assert for pointerCoords axes
+ coords.bits = args.pointerCoords[i].bits;
+ coords.values = std::vector<float>(args.pointerCoords[i].values,
+ args.pointerCoords[i].values +
+ BitSet64::count(args.pointerCoords[i].bits));
+ outPointerCoords.push_back(coords);
+ }
+}
+
+common::MotionEvent notifyMotionArgsToHalMotionEvent(const NotifyMotionArgs& args) {
+ common::MotionEvent event;
+ event.deviceId = args.deviceId;
+ event.source = getSource(args.source);
+ event.displayId = args.displayId;
+ event.downTime = args.downTime;
+ event.eventTime = args.eventTime;
+ event.deviceTimestamp = 0;
+ event.action = getAction(args.action & AMOTION_EVENT_ACTION_MASK);
+ event.actionIndex = MotionEvent::getActionIndex(args.action);
+ event.actionButton = getActionButton(args.actionButton);
+ event.flags = getFlags(args.flags);
+ event.policyFlags = getPolicyFlags(args.policyFlags);
+ event.edgeFlags = getEdgeFlags(args.edgeFlags);
+ event.metaState = getMetastate(args.metaState);
+ event.buttonState = getButtonState(args.buttonState);
+ event.xPrecision = args.xPrecision;
+ event.yPrecision = args.yPrecision;
+
+ std::vector<common::PointerProperties> pointerProperties;
+ std::vector<common::PointerCoords> pointerCoords;
+ getHalPropertiesAndCoords(args, /*out*/ pointerProperties, /*out*/ pointerCoords);
+ event.pointerProperties = pointerProperties;
+ event.pointerCoords = pointerCoords;
+
+ event.frames = convertVideoFrames(args.videoFrames);
+
+ return event;
+}
+
+} // namespace android
diff --git a/services/inputflinger/InputClassifierConverter.h b/services/inputflinger/InputCommonConverter.h
similarity index 65%
rename from services/inputflinger/InputClassifierConverter.h
rename to services/inputflinger/InputCommonConverter.h
index 5154b0b..4d3b768 100644
--- a/services/inputflinger/InputClassifierConverter.h
+++ b/services/inputflinger/InputCommonConverter.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,21 +14,18 @@
* limitations under the License.
*/
-#ifndef _UI_INPUT_CLASSIFIER_CONVERTER_H
-#define _UI_INPUT_CLASSIFIER_CONVERTER_H
+#pragma once
+#include <aidl/android/hardware/input/common/Axis.h>
+#include <aidl/android/hardware/input/common/MotionEvent.h>
#include "InputListener.h"
-#include <android/hardware/input/common/1.0/types.h>
-
namespace android {
/**
- * Convert from framework's NotifyMotionArgs to hidl's common::V1_0::MotionEvent
+ * Convert from framework's NotifyMotionArgs to hidl's common::MotionEvent
*/
-::android::hardware::input::common::V1_0::MotionEvent notifyMotionArgsToHalMotionEvent(
+::aidl::android::hardware::input::common::MotionEvent notifyMotionArgsToHalMotionEvent(
const NotifyMotionArgs& args);
} // namespace android
-
-#endif // _UI_INPUT_CLASSIFIER_CONVERTER_H
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 7a9862d..7b03631 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -33,8 +33,6 @@
namespace android {
using gui::FocusRequest;
-using gui::WindowInfo;
-using gui::WindowInfoHandle;
static int32_t exceptionCodeFromStatusT(status_t status) {
switch (status) {
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index 41e9ce2..cd20a64 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -193,7 +193,6 @@
void updateInfo() {
mInfo.token = mClientChannel->getConnectionToken();
mInfo.name = "FakeWindowHandle";
- mInfo.type = WindowInfo::Type::APPLICATION;
mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
mInfo.frameLeft = mFrame.left;
mInfo.frameTop = mFrame.top;
@@ -202,10 +201,6 @@
mInfo.globalScaleFactor = 1.0;
mInfo.touchableRegion.clear();
mInfo.addTouchableRegion(mFrame);
- mInfo.visible = true;
- mInfo.focusable = true;
- mInfo.hasWallpaper = false;
- mInfo.paused = false;
mInfo.ownerPid = INJECTOR_PID;
mInfo.ownerUid = INJECTOR_UID;
mInfo.displayId = ADISPLAY_ID_DEFAULT;
diff --git a/services/inputflinger/dispatcher/FocusResolver.cpp b/services/inputflinger/dispatcher/FocusResolver.cpp
index 600f02b..a02b3e8 100644
--- a/services/inputflinger/dispatcher/FocusResolver.cpp
+++ b/services/inputflinger/dispatcher/FocusResolver.cpp
@@ -148,11 +148,11 @@
continue;
}
windowFound = true;
- if (window->getInfo()->visible) {
+ if (!window->getInfo()->inputConfig.test(gui::WindowInfo::InputConfig::NOT_VISIBLE)) {
// Check if at least a single window is visible.
visibleWindowFound = true;
}
- if (!window->getInfo()->focusable) {
+ if (window->getInfo()->inputConfig.test(gui::WindowInfo::InputConfig::NOT_FOCUSABLE)) {
// Check if all windows with the window token are focusable.
allWindowsAreFocusable = false;
break;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 6c321bc..58c9303 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -500,17 +500,16 @@
// Returns true if the given window can accept pointer events at the given display location.
bool windowAcceptsTouchAt(const WindowInfo& windowInfo, int32_t displayId, int32_t x, int32_t y,
bool isStylus) {
- if (windowInfo.displayId != displayId || !windowInfo.visible) {
+ const auto inputConfig = windowInfo.inputConfig;
+ if (windowInfo.displayId != displayId ||
+ inputConfig.test(WindowInfo::InputConfig::NOT_VISIBLE)) {
return false;
}
- const auto flags = windowInfo.flags;
const bool windowCanInterceptTouch = isStylus && windowInfo.interceptsStylus();
- if (flags.test(WindowInfo::Flag::NOT_TOUCHABLE) && !windowCanInterceptTouch) {
+ if (inputConfig.test(WindowInfo::InputConfig::NOT_TOUCHABLE) && !windowCanInterceptTouch) {
return false;
}
- const bool isModalWindow = !flags.test(WindowInfo::Flag::NOT_FOCUSABLE) &&
- !flags.test(WindowInfo::Flag::NOT_TOUCH_MODAL);
- if (!isModalWindow && !windowInfo.touchableRegionContainsPoint(x, y)) {
+ if (!windowInfo.touchableRegionContainsPoint(x, y)) {
return false;
}
return true;
@@ -1047,7 +1046,8 @@
return windowHandle;
}
- if (addOutsideTargets && info.flags.test(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH)) {
+ if (addOutsideTargets &&
+ info.inputConfig.test(WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH)) {
touchState->addOrUpdateWindow(windowHandle, InputTarget::FLAG_DISPATCH_AS_OUTSIDE,
BitSet32(0));
}
@@ -1900,7 +1900,8 @@
return InputEventInjectionResult::PERMISSION_DENIED;
}
- if (focusedWindowHandle->getInfo()->paused) {
+ if (focusedWindowHandle->getInfo()->inputConfig.test(
+ WindowInfo::InputConfig::PAUSE_DISPATCHING)) {
ALOGI("Waiting because %s is paused", focusedWindowHandle->getName().c_str());
return InputEventInjectionResult::PENDING;
}
@@ -2101,7 +2102,7 @@
for (const sp<WindowInfoHandle>& windowHandle : newTouchedWindows) {
const WindowInfo& info = *windowHandle->getInfo();
- if (info.paused) {
+ if (info.inputConfig.test(WindowInfo::InputConfig::PAUSE_DISPATCHING)) {
ALOGI("Not sending touch event to %s because it is paused",
windowHandle->getName().c_str());
continue;
@@ -2324,13 +2325,16 @@
if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
sp<WindowInfoHandle> foregroundWindowHandle =
tempTouchState.getFirstForegroundWindowHandle();
- if (foregroundWindowHandle && foregroundWindowHandle->getInfo()->hasWallpaper) {
+ if (foregroundWindowHandle &&
+ foregroundWindowHandle->getInfo()->inputConfig.test(
+ WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) {
const std::vector<sp<WindowInfoHandle>>& windowHandles =
getWindowHandlesLocked(displayId);
for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {
const WindowInfo* info = windowHandle->getInfo();
if (info->displayId == displayId &&
- windowHandle->getInfo()->type == WindowInfo::Type::WALLPAPER) {
+ windowHandle->getInfo()->inputConfig.test(
+ WindowInfo::InputConfig::IS_WALLPAPER)) {
tempTouchState
.addOrUpdateWindow(windowHandle,
InputTarget::FLAG_WINDOW_IS_OBSCURED |
@@ -2599,9 +2603,10 @@
}
auto info = windowHandle->getInfo();
auto otherInfo = otherHandle->getInfo();
- if (!otherInfo->visible) {
+ if (otherInfo->inputConfig.test(WindowInfo::InputConfig::NOT_VISIBLE)) {
return false;
- } else if (otherInfo->alpha == 0 && otherInfo->flags.test(WindowInfo::Flag::NOT_TOUCHABLE)) {
+ } else if (otherInfo->alpha == 0 &&
+ otherInfo->inputConfig.test(WindowInfo::InputConfig::NOT_TOUCHABLE)) {
// Those act as if they were invisible, so we don't need to flag them.
// We do want to potentially flag touchable windows even if they have 0
// opacity, since they can consume touches and alter the effects of the
@@ -2613,7 +2618,7 @@
// If ownerUid is the same we don't generate occlusion events as there
// is no security boundary within an uid.
return false;
- } else if (otherInfo->trustedOverlay) {
+ } else if (otherInfo->inputConfig.test(gui::WindowInfo::InputConfig::TRUSTED_OVERLAY)) {
return false;
} else if (otherInfo->displayId != info->displayId) {
return false;
@@ -2694,17 +2699,17 @@
std::string InputDispatcher::dumpWindowForTouchOcclusion(const WindowInfo* info,
bool isTouchedWindow) const {
return StringPrintf(INDENT2
- "* %stype=%s, package=%s/%" PRId32 ", id=%" PRId32 ", mode=%s, alpha=%.2f, "
+ "* %spackage=%s/%" PRId32 ", id=%" PRId32 ", mode=%s, alpha=%.2f, "
"frame=[%" PRId32 ",%" PRId32 "][%" PRId32 ",%" PRId32
- "], touchableRegion=%s, window={%s}, flags={%s}, inputFeatures={%s}, "
+ "], touchableRegion=%s, window={%s}, inputConfig={%s}, inputFeatures={%s}, "
"hasToken=%s, applicationInfo.name=%s, applicationInfo.token=%s\n",
- isTouchedWindow ? "[TOUCHED] " : "", ftl::enum_string(info->type).c_str(),
- info->packageName.c_str(), info->ownerUid, info->id,
- toString(info->touchOcclusionMode).c_str(), info->alpha, info->frameLeft,
- info->frameTop, info->frameRight, info->frameBottom,
- dumpRegion(info->touchableRegion).c_str(), info->name.c_str(),
- info->flags.string().c_str(), info->inputFeatures.string().c_str(),
- toString(info->token != nullptr), info->applicationInfo.name.c_str(),
+ isTouchedWindow ? "[TOUCHED] " : "", info->packageName.c_str(),
+ info->ownerUid, info->id, toString(info->touchOcclusionMode).c_str(),
+ info->alpha, info->frameLeft, info->frameTop, info->frameRight,
+ info->frameBottom, dumpRegion(info->touchableRegion).c_str(),
+ info->name.c_str(), info->inputConfig.string().c_str(),
+ info->inputFeatures.string().c_str(), toString(info->token != nullptr),
+ info->applicationInfo.name.c_str(),
toString(info->applicationInfo.token).c_str());
}
@@ -4572,8 +4577,9 @@
if (getInputChannelLocked(handle->getToken()) == nullptr) {
const bool noInputChannel =
info->inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL);
- const bool canReceiveInput = !info->flags.test(WindowInfo::Flag::NOT_TOUCHABLE) ||
- !info->flags.test(WindowInfo::Flag::NOT_FOCUSABLE);
+ const bool canReceiveInput =
+ !info->inputConfig.test(WindowInfo::InputConfig::NOT_TOUCHABLE) ||
+ !info->inputConfig.test(WindowInfo::InputConfig::NOT_FOCUSABLE);
if (canReceiveInput && !noInputChannel) {
ALOGV("Window handle %s has no registered input channel",
handle->getName().c_str());
@@ -4644,12 +4650,16 @@
}
// Ensure all spy windows are trusted overlays
- LOG_ALWAYS_FATAL_IF(info.isSpy() && !info.trustedOverlay,
+ LOG_ALWAYS_FATAL_IF(info.isSpy() &&
+ !info.inputConfig.test(
+ WindowInfo::InputConfig::TRUSTED_OVERLAY),
"%s has feature SPY, but is not a trusted overlay.",
window->getName().c_str());
// Ensure all stylus interceptors are trusted overlays
- LOG_ALWAYS_FATAL_IF(info.interceptsStylus() && !info.trustedOverlay,
+ LOG_ALWAYS_FATAL_IF(info.interceptsStylus() &&
+ !info.inputConfig.test(
+ WindowInfo::InputConfig::TRUSTED_OVERLAY),
"%s has feature INTERCEPTS_STYLUS, but is not a trusted overlay.",
window->getName().c_str());
}
@@ -4699,7 +4709,8 @@
// Since we are about to drop the touch, cancel the events for the wallpaper as
// well.
if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND &&
- touchedWindow.windowHandle->getInfo()->hasWallpaper) {
+ touchedWindow.windowHandle->getInfo()->inputConfig.test(
+ gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) {
sp<WindowInfoHandle> wallpaper = state.getWallpaperWindow();
if (wallpaper != nullptr) {
sp<Connection> wallpaperConnection =
@@ -4920,7 +4931,7 @@
const sp<IBinder> focusedToken =
mFocusResolver.getFocusedWindowToken(mFocusedDisplayId);
- // TODO(b/198487159): if no window is currently focused, then we need to check the last
+ // TODO(b/218541064): if no window is currently focused, then we need to check the last
// interacted window (within 1 second timeout). We should allow touch mode change
// if the last interacted window owner's pid/uid match the calling ones.
if (focusedToken == nullptr) {
@@ -5194,34 +5205,27 @@
const WindowInfo* windowInfo = windowHandle->getInfo();
dump += StringPrintf(INDENT3 "%zu: name='%s', id=%" PRId32 ", displayId=%d, "
- "paused=%s, focusable=%s, "
- "hasWallpaper=%s, visible=%s, alpha=%.2f, "
- "flags=%s, type=%s, "
+ "inputConfig=%s, alpha=%.2f, "
"frame=[%d,%d][%d,%d], globalScale=%f, "
"applicationInfo.name=%s, "
"applicationInfo.token=%s, "
"touchableRegion=",
i, windowInfo->name.c_str(), windowInfo->id,
- windowInfo->displayId, toString(windowInfo->paused),
- toString(windowInfo->focusable),
- toString(windowInfo->hasWallpaper),
- toString(windowInfo->visible), windowInfo->alpha,
- windowInfo->flags.string().c_str(),
- ftl::enum_string(windowInfo->type).c_str(),
- windowInfo->frameLeft, windowInfo->frameTop,
- windowInfo->frameRight, windowInfo->frameBottom,
- windowInfo->globalScaleFactor,
+ windowInfo->displayId,
+ windowInfo->inputConfig.string().c_str(),
+ windowInfo->alpha, windowInfo->frameLeft,
+ windowInfo->frameTop, windowInfo->frameRight,
+ windowInfo->frameBottom, windowInfo->globalScaleFactor,
windowInfo->applicationInfo.name.c_str(),
toString(windowInfo->applicationInfo.token).c_str());
dump += dumpRegion(windowInfo->touchableRegion);
dump += StringPrintf(", inputFeatures=%s",
windowInfo->inputFeatures.string().c_str());
dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%" PRId64
- "ms, trustedOverlay=%s, hasToken=%s, "
+ "ms, hasToken=%s, "
"touchOcclusionMode=%s\n",
windowInfo->ownerPid, windowInfo->ownerUid,
millis(windowInfo->dispatchingTimeout),
- toString(windowInfo->trustedOverlay),
toString(windowInfo->token != nullptr),
toString(windowInfo->touchOcclusionMode).c_str());
windowInfo->transform.dump(dump, "transform", INDENT4);
diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp
index b63fe10..61e78cc 100644
--- a/services/inputflinger/dispatcher/TouchState.cpp
+++ b/services/inputflinger/dispatcher/TouchState.cpp
@@ -100,7 +100,8 @@
for (const TouchedWindow& window : windows) {
if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
if (haveSlipperyForegroundWindow ||
- !window.windowHandle->getInfo()->flags.test(WindowInfo::Flag::SLIPPERY)) {
+ !window.windowHandle->getInfo()->inputConfig.test(
+ WindowInfo::InputConfig::SLIPPERY)) {
return false;
}
haveSlipperyForegroundWindow = true;
@@ -112,7 +113,8 @@
sp<WindowInfoHandle> TouchState::getWallpaperWindow() const {
for (size_t i = 0; i < windows.size(); i++) {
const TouchedWindow& window = windows[i];
- if (window.windowHandle->getInfo()->type == WindowInfo::Type::WALLPAPER) {
+ if (window.windowHandle->getInfo()->inputConfig.test(
+ gui::WindowInfo::InputConfig::IS_WALLPAPER)) {
return window.windowHandle;
}
}
diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp
index 51546ce..3bd3275 100644
--- a/services/inputflinger/reader/Android.bp
+++ b/services/inputflinger/reader/Android.bp
@@ -71,6 +71,7 @@
"libstatslog",
"libui",
"libutils",
+ "PlatformProperties",
],
static_libs: [
"libc++fs",
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index db67877..8bd3899 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -685,7 +685,7 @@
mEpollFd = epoll_create1(EPOLL_CLOEXEC);
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
- mINotifyFd = inotify_init();
+ mINotifyFd = inotify_init1(IN_CLOEXEC);
std::error_code errorCode;
bool isDeviceInotifyAdded = false;
@@ -713,7 +713,7 @@
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance. errno=%d", errno);
int wakeFds[2];
- result = pipe(wakeFds);
+ result = pipe2(wakeFds, O_CLOEXEC);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);
mWakeReadPipeFd = wakeFds[0];
diff --git a/services/inputflinger/reader/TouchVideoDevice.cpp b/services/inputflinger/reader/TouchVideoDevice.cpp
index c7c8e28..2f8138b 100644
--- a/services/inputflinger/reader/TouchVideoDevice.cpp
+++ b/services/inputflinger/reader/TouchVideoDevice.cpp
@@ -49,7 +49,7 @@
};
std::unique_ptr<TouchVideoDevice> TouchVideoDevice::create(std::string devicePath) {
- unique_fd fd(open(devicePath.c_str(), O_RDWR | O_NONBLOCK));
+ unique_fd fd(open(devicePath.c_str(), O_RDWR | O_NONBLOCK | O_CLOEXEC));
if (fd.get() == INVALID_FD) {
ALOGE("Could not open video device %s: %s", devicePath.c_str(), strerror(errno));
return nullptr;
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
index ff3a592..41a8426 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
@@ -18,6 +18,8 @@
#include "MultiTouchInputMapper.h"
+#include <android/sysprop/InputProperties.sysprop.h>
+
namespace android {
// --- Constants ---
@@ -309,6 +311,10 @@
outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
}
}
+ if (shouldSimulateStylusWithTouch() &&
+ outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER) {
+ outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+ }
bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE &&
(mTouchButtonAccumulator.isHovering() ||
@@ -385,7 +391,15 @@
}
bool MultiTouchInputMapper::hasStylus() const {
- return mMultiTouchMotionAccumulator.hasStylus() || mTouchButtonAccumulator.hasStylus();
+ return mMultiTouchMotionAccumulator.hasStylus() || mTouchButtonAccumulator.hasStylus() ||
+ shouldSimulateStylusWithTouch();
+}
+
+bool MultiTouchInputMapper::shouldSimulateStylusWithTouch() const {
+ static const bool SIMULATE_STYLUS_WITH_TOUCH =
+ sysprop::InputProperties::simulate_stylus_with_touch().value_or(false);
+ return SIMULATE_STYLUS_WITH_TOUCH &&
+ mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN;
}
} // namespace android
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
index 225ad49..b7c3457 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
@@ -104,6 +104,14 @@
bool hasStylus() const override;
private:
+ // simulate_stylus_with_touch is a debug mode that converts all finger pointers reported by this
+ // mapper's touchscreen into stylus pointers, and adds SOURCE_STYLUS to the input device.
+ // It is used to simulate stylus events for debugging and testing on a device that does not
+ // support styluses. It can be enabled using
+ // "adb shell setprop persist.debug.input.simulate_stylus_with_touch true",
+ // and requires a reboot to take effect.
+ inline bool shouldSimulateStylusWithTouch() const;
+
// If the slot is in use, return the bit id. Return std::nullopt otherwise.
std::optional<int32_t> getActiveBitId(const MultiTouchMotionAccumulator::Slot& inSlot);
MultiTouchMotionAccumulator mMultiTouchMotionAccumulator;
diff --git a/services/inputflinger/tests/FocusResolver_test.cpp b/services/inputflinger/tests/FocusResolver_test.cpp
index 662be80..ffce9f6 100644
--- a/services/inputflinger/tests/FocusResolver_test.cpp
+++ b/services/inputflinger/tests/FocusResolver_test.cpp
@@ -37,12 +37,16 @@
bool visible) {
mInfo.token = token;
mInfo.name = name;
- mInfo.visible = visible;
- mInfo.focusable = focusable;
+ setFocusable(focusable);
+ setVisible(visible);
}
- void setFocusable(bool focusable) { mInfo.focusable = focusable; }
- void setVisible(bool visible) { mInfo.visible = visible; }
+ void setFocusable(bool focusable) {
+ mInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_FOCUSABLE, !focusable);
+ }
+ void setVisible(bool visible) {
+ mInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_VISIBLE, !visible);
+ }
};
TEST(FocusResolverTest, SetFocusedWindow) {
diff --git a/services/inputflinger/tests/InputClassifierConverter_test.cpp b/services/inputflinger/tests/InputClassifierConverter_test.cpp
index f626d56..81ef9b9 100644
--- a/services/inputflinger/tests/InputClassifierConverter_test.cpp
+++ b/services/inputflinger/tests/InputClassifierConverter_test.cpp
@@ -14,13 +14,13 @@
* limitations under the License.
*/
-#include "../InputClassifierConverter.h"
+#include "../InputCommonConverter.h"
#include <gtest/gtest.h>
#include <gui/constants.h>
#include <utils/BitSet.h>
-using namespace android::hardware::input;
+using namespace aidl::android::hardware::input;
namespace android {
@@ -50,8 +50,7 @@
return motionArgs;
}
-static float getMotionEventAxis(common::V1_0::PointerCoords coords,
- common::V1_0::Axis axis) {
+static float getMotionEventAxis(common::PointerCoords coords, common::Axis axis) {
uint32_t index = BitSet64::getIndexOfBit(static_cast<uint64_t>(coords.bits),
static_cast<uint64_t>(axis));
return coords.values[index];
@@ -68,14 +67,14 @@
ASSERT_EQ(0.5, motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_SIZE));
ASSERT_EQ(3U, BitSet64::count(motionArgs.pointerCoords[0].bits));
- common::V1_0::MotionEvent motionEvent = notifyMotionArgsToHalMotionEvent(motionArgs);
+ common::MotionEvent motionEvent = notifyMotionArgsToHalMotionEvent(motionArgs);
- ASSERT_EQ(getMotionEventAxis(motionEvent.pointerCoords[0], common::V1_0::Axis::X),
- motionArgs.pointerCoords[0].getX());
- ASSERT_EQ(getMotionEventAxis(motionEvent.pointerCoords[0], common::V1_0::Axis::Y),
- motionArgs.pointerCoords[0].getY());
- ASSERT_EQ(getMotionEventAxis(motionEvent.pointerCoords[0], common::V1_0::Axis::SIZE),
- motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_SIZE));
+ ASSERT_EQ(getMotionEventAxis(motionEvent.pointerCoords[0], common::Axis::X),
+ motionArgs.pointerCoords[0].getX());
+ ASSERT_EQ(getMotionEventAxis(motionEvent.pointerCoords[0], common::Axis::Y),
+ motionArgs.pointerCoords[0].getY());
+ ASSERT_EQ(getMotionEventAxis(motionEvent.pointerCoords[0], common::Axis::SIZE),
+ motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_SIZE));
ASSERT_EQ(BitSet64::count(motionArgs.pointerCoords[0].bits),
BitSet64::count(motionEvent.pointerCoords[0].bits));
}
diff --git a/services/inputflinger/tests/InputClassifier_test.cpp b/services/inputflinger/tests/InputClassifier_test.cpp
index f13187d..3a77127 100644
--- a/services/inputflinger/tests/InputClassifier_test.cpp
+++ b/services/inputflinger/tests/InputClassifier_test.cpp
@@ -20,12 +20,14 @@
#include "TestInputListener.h"
-#include <android/hardware/input/classifier/1.0/IInputClassifier.h>
+#include <aidl/android/hardware/input/processor/BnInputProcessor.h>
+#include <aidl/android/hardware/input/processor/IInputProcessor.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
-using namespace android::hardware::input;
-using android::hardware::Return;
-using android::hardware::Void;
-using android::hardware::input::common::V1_0::Classification;
+using namespace aidl::android::hardware::input;
+using aidl::android::hardware::input::common::Classification;
+using aidl::android::hardware::input::processor::IInputProcessor;
namespace android {
@@ -154,22 +156,17 @@
/**
* A minimal implementation of IInputClassifier.
*/
-struct TestHal : public android::hardware::input::classifier::V1_0::IInputClassifier {
- Return<Classification> classify(
- const android::hardware::input::common::V1_0::MotionEvent& event) override {
- return Classification::NONE;
- };
- Return<void> reset() override { return Void(); };
- Return<void> resetDevice(int32_t deviceId) override { return Void(); };
-};
-
-/**
- * An entity that will be subscribed to the HAL death.
- */
-class TestDeathRecipient : public android::hardware::hidl_death_recipient {
-public:
- virtual void serviceDied(uint64_t cookie,
- const wp<android::hidl::base::V1_0::IBase>& who) override{};
+class TestHal : public aidl::android::hardware::input::processor::BnInputProcessor {
+ ::ndk::ScopedAStatus classify(
+ const ::aidl::android::hardware::input::common::MotionEvent& in_event,
+ ::aidl::android::hardware::input::common::Classification* _aidl_return) override {
+ *_aidl_return = Classification::NONE;
+ return ndk::ScopedAStatus::ok();
+ }
+ ::ndk::ScopedAStatus reset() override { return ndk::ScopedAStatus::ok(); }
+ ::ndk::ScopedAStatus resetDevice(int32_t in_deviceId) override {
+ return ndk::ScopedAStatus::ok();
+ }
};
// --- MotionClassifierTest ---
@@ -178,15 +175,9 @@
protected:
std::unique_ptr<MotionClassifierInterface> mMotionClassifier;
- virtual void SetUp() override {
- mMotionClassifier = MotionClassifier::create(new TestDeathRecipient());
- if (mMotionClassifier == nullptr) {
- // If the device running this test does not have IInputClassifier service,
- // use the test HAL instead.
- // Using 'new' to access non-public constructor
- mMotionClassifier =
- std::unique_ptr<MotionClassifier>(new MotionClassifier(new TestHal()));
- }
+ void SetUp() override {
+ std::shared_ptr<IInputProcessor> service = ndk::SharedRefBase::make<TestHal>();
+ mMotionClassifier = MotionClassifier::create(std::move(service));
}
};
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 872882e..ae8358a 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -21,6 +21,7 @@
#include <android-base/stringprintf.h>
#include <android-base/thread_annotations.h>
#include <binder/Binder.h>
+#include <fcntl.h>
#include <gtest/gtest.h>
#include <input/Input.h>
#include <linux/input.h>
@@ -986,7 +987,6 @@
mInfo.token = *token;
mInfo.id = sId++;
mInfo.name = name;
- mInfo.type = WindowInfo::Type::APPLICATION;
mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
mInfo.alpha = 1.0;
mInfo.frameLeft = 0;
@@ -997,14 +997,10 @@
mInfo.globalScaleFactor = 1.0;
mInfo.touchableRegion.clear();
mInfo.addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT));
- mInfo.visible = true;
- mInfo.focusable = false;
- mInfo.hasWallpaper = false;
- mInfo.paused = false;
mInfo.ownerPid = INJECTOR_PID;
mInfo.ownerUid = INJECTOR_UID;
mInfo.displayId = displayId;
- mInfo.trustedOverlay = false;
+ mInfo.inputConfig = WindowInfo::InputConfig::NONE;
}
sp<FakeWindowHandle> clone(
@@ -1016,15 +1012,37 @@
return handle;
}
- void setFocusable(bool focusable) { mInfo.focusable = focusable; }
+ void setTouchable(bool touchable) {
+ mInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, !touchable);
+ }
- void setVisible(bool visible) { mInfo.visible = visible; }
+ void setFocusable(bool focusable) {
+ mInfo.setInputConfig(WindowInfo::InputConfig::NOT_FOCUSABLE, !focusable);
+ }
+
+ void setVisible(bool visible) {
+ mInfo.setInputConfig(WindowInfo::InputConfig::NOT_VISIBLE, !visible);
+ }
void setDispatchingTimeout(std::chrono::nanoseconds timeout) {
mInfo.dispatchingTimeout = timeout;
}
- void setPaused(bool paused) { mInfo.paused = paused; }
+ void setPaused(bool paused) {
+ mInfo.setInputConfig(WindowInfo::InputConfig::PAUSE_DISPATCHING, paused);
+ }
+
+ void setPreventSplitting(bool preventSplitting) {
+ mInfo.setInputConfig(WindowInfo::InputConfig::PREVENT_SPLITTING, preventSplitting);
+ }
+
+ void setSlippery(bool slippery) {
+ mInfo.setInputConfig(WindowInfo::InputConfig::SLIPPERY, slippery);
+ }
+
+ void setWatchOutsideTouch(bool watchOutside) {
+ mInfo.setInputConfig(WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH, watchOutside);
+ }
void setAlpha(float alpha) { mInfo.alpha = alpha; }
@@ -1048,17 +1066,19 @@
void setTouchableRegion(const Region& region) { mInfo.touchableRegion = region; }
- void setType(WindowInfo::Type type) { mInfo.type = type; }
+ void setIsWallpaper(bool isWallpaper) {
+ mInfo.setInputConfig(WindowInfo::InputConfig::IS_WALLPAPER, isWallpaper);
+ }
- void setHasWallpaper(bool hasWallpaper) { mInfo.hasWallpaper = hasWallpaper; }
-
- void addFlags(Flags<WindowInfo::Flag> flags) { mInfo.flags |= flags; }
-
- void setFlags(Flags<WindowInfo::Flag> flags) { mInfo.flags = flags; }
+ void setDupTouchToWallpaper(bool hasWallpaper) {
+ mInfo.setInputConfig(WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER, hasWallpaper);
+ }
void setInputFeatures(Flags<WindowInfo::Feature> features) { mInfo.inputFeatures = features; }
- void setTrustedOverlay(bool trustedOverlay) { mInfo.trustedOverlay = trustedOverlay; }
+ void setTrustedOverlay(bool trustedOverlay) {
+ mInfo.setInputConfig(WindowInfo::InputConfig::TRUSTED_OVERLAY, trustedOverlay);
+ }
void setWindowTransform(float dsdx, float dtdx, float dtdy, float dsdy) {
mInfo.transform.set(dsdx, dtdx, dtdy, dsdy);
@@ -1539,19 +1559,15 @@
}
/**
- * Calling setInputWindows once with FLAG_NOT_TOUCH_MODAL should not cause any issues.
- * To ensure that window receives only events that were directly inside of it, add
- * FLAG_NOT_TOUCH_MODAL. This will enforce using the touchableRegion of the input
- * when finding touched windows.
+ * Calling setInputWindows once should not cause any issues.
* This test serves as a sanity check for the next test, where setInputWindows is
* called twice.
*/
-TEST_F(InputDispatcherTest, SetInputWindowOnce_SingleWindowTouch) {
+TEST_F(InputDispatcherTest, SetInputWindowOnceWithSingleTouchWindow) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
window->setFrame(Rect(0, 0, 100, 100));
- window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -1565,16 +1581,12 @@
/**
* Calling setInputWindows twice, with the same info, should not cause any issues.
- * To ensure that window receives only events that were directly inside of it, add
- * FLAG_NOT_TOUCH_MODAL. This will enforce using the touchableRegion of the input
- * when finding touched windows.
*/
TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
window->setFrame(Rect(0, 0, 100, 100));
- window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -1609,17 +1621,17 @@
* Two windows: A top window, and a wallpaper behind the window.
* Touch goes to the top window, and then top window disappears. Ensure that wallpaper window
* gets ACTION_CANCEL.
- * 1. foregroundWindow <-- has wallpaper (hasWallpaper=true)
- * 2. wallpaperWindow <-- is wallpaper (type=InputWindowInfo::Type::WALLPAPER)
+ * 1. foregroundWindow <-- dup touch to wallpaper
+ * 2. wallpaperWindow <-- is wallpaper
*/
TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCanceled) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> foregroundWindow =
new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
- foregroundWindow->setHasWallpaper(true);
+ foregroundWindow->setDupTouchToWallpaper(true);
sp<FakeWindowHandle> wallpaperWindow =
new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
- wallpaperWindow->setType(WindowInfo::Type::WALLPAPER);
+ wallpaperWindow->setIsWallpaper(true);
constexpr int expectedWallpaperFlags =
AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
@@ -1660,10 +1672,10 @@
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> foregroundWindow =
new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
- foregroundWindow->setHasWallpaper(true);
+ foregroundWindow->setDupTouchToWallpaper(true);
sp<FakeWindowHandle> wallpaperWindow =
new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
- wallpaperWindow->setType(WindowInfo::Type::WALLPAPER);
+ wallpaperWindow->setIsWallpaper(true);
constexpr int expectedWallpaperFlags =
AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
@@ -1704,11 +1716,11 @@
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
- window->setHasWallpaper(true);
+ window->setDupTouchToWallpaper(true);
sp<FakeWindowHandle> wallpaperWindow =
new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
- wallpaperWindow->setType(WindowInfo::Type::WALLPAPER);
+ wallpaperWindow->setIsWallpaper(true);
constexpr int expectedWallpaperFlags =
AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
@@ -1762,19 +1774,17 @@
sp<FakeWindowHandle> leftWindow =
new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
leftWindow->setFrame(Rect(0, 0, 200, 200));
- leftWindow->setFlags(WindowInfo::Flag::SPLIT_TOUCH | WindowInfo::Flag::NOT_TOUCH_MODAL);
- leftWindow->setHasWallpaper(true);
+ leftWindow->setDupTouchToWallpaper(true);
sp<FakeWindowHandle> rightWindow =
new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
rightWindow->setFrame(Rect(200, 0, 400, 200));
- rightWindow->setFlags(WindowInfo::Flag::SPLIT_TOUCH | WindowInfo::Flag::NOT_TOUCH_MODAL);
- rightWindow->setHasWallpaper(true);
+ rightWindow->setDupTouchToWallpaper(true);
sp<FakeWindowHandle> wallpaperWindow =
new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
wallpaperWindow->setFrame(Rect(0, 0, 400, 200));
- wallpaperWindow->setType(WindowInfo::Type::WALLPAPER);
+ wallpaperWindow->setIsWallpaper(true);
constexpr int expectedWallpaperFlags =
AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
@@ -1848,11 +1858,9 @@
sp<FakeWindowHandle> windowLeft =
new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
windowLeft->setFrame(Rect(0, 0, 600, 800));
- windowLeft->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
sp<FakeWindowHandle> windowRight =
new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
windowRight->setFrame(Rect(600, 0, 1200, 800));
- windowRight->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -1959,7 +1967,6 @@
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
window->setFrame(Rect(0, 0, 1200, 800));
- window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -2041,11 +2048,9 @@
sp<FakeWindowHandle> windowLeft =
new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
windowLeft->setFrame(Rect(0, 0, 600, 800));
- windowLeft->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
sp<FakeWindowHandle> windowRight =
new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
windowRight->setFrame(Rect(600, 0, 1200, 800));
- windowRight->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -2151,14 +2156,12 @@
// Add two windows to the display. Their frames are represented in the display space.
sp<FakeWindowHandle> firstWindow =
new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
- firstWindow->addFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
firstWindow->setFrame(Rect(0, 0, 100, 200), displayTransform);
addWindow(firstWindow);
sp<FakeWindowHandle> secondWindow =
new FakeWindowHandle(application, mDispatcher, "Second Window",
ADISPLAY_ID_DEFAULT);
- secondWindow->addFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
secondWindow->setFrame(Rect(100, 200, 200, 400), displayTransform);
addWindow(secondWindow);
return {std::move(firstWindow), std::move(secondWindow)};
@@ -2301,8 +2304,10 @@
// Create a couple of windows
sp<FakeWindowHandle> firstWindow =
new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
+ firstWindow->setPreventSplitting(true);
sp<FakeWindowHandle> secondWindow =
new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
+ secondWindow->setPreventSplitting(true);
// Add the windows to the dispatcher
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}});
@@ -2375,17 +2380,13 @@
TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- // Create a non touch modal window that supports split touch
sp<FakeWindowHandle> firstWindow =
new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
firstWindow->setFrame(Rect(0, 0, 600, 400));
- firstWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
- // Create a non touch modal window that supports split touch
sp<FakeWindowHandle> secondWindow =
new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
secondWindow->setFrame(Rect(0, 400, 600, 800));
- secondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
// Add the windows to the dispatcher
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}});
@@ -2447,17 +2448,13 @@
TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- // Create a non touch modal window that supports split touch
sp<FakeWindowHandle> firstWindow =
new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
firstWindow->setFrame(Rect(0, 0, 600, 400));
- firstWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
- // Create a non touch modal window that supports split touch
sp<FakeWindowHandle> secondWindow =
new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
secondWindow->setFrame(Rect(0, 400, 600, 800));
- secondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
// Add the windows to the dispatcher
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}});
@@ -2522,26 +2519,21 @@
sp<FakeWindowHandle> firstWindowInPrimary =
new FakeWindowHandle(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
- firstWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
sp<FakeWindowHandle> secondWindowInPrimary =
new FakeWindowHandle(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
- secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
sp<FakeWindowHandle> mirrorWindowInPrimary =
firstWindowInPrimary->clone(application, mDispatcher, ADISPLAY_ID_DEFAULT);
mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200));
- mirrorWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
sp<FakeWindowHandle> firstWindowInSecondary =
firstWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID);
firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100));
- firstWindowInSecondary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
sp<FakeWindowHandle> secondWindowInSecondary =
secondWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID);
secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
- secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
// Update window info, let it find window handle of second display first.
mDispatcher->setInputWindows(
@@ -2586,26 +2578,21 @@
sp<FakeWindowHandle> firstWindowInPrimary =
new FakeWindowHandle(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
- firstWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
sp<FakeWindowHandle> secondWindowInPrimary =
new FakeWindowHandle(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
- secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
sp<FakeWindowHandle> mirrorWindowInPrimary =
firstWindowInPrimary->clone(application, mDispatcher, ADISPLAY_ID_DEFAULT);
mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200));
- mirrorWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
sp<FakeWindowHandle> firstWindowInSecondary =
firstWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID);
firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100));
- firstWindowInSecondary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
sp<FakeWindowHandle> secondWindowInSecondary =
secondWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID);
secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
- secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
// Update window info, let it find window handle of second display first.
mDispatcher->setInputWindows(
@@ -2699,17 +2686,13 @@
TEST_F(InputDispatcherTest, PointerCancel_SendCancelWhenSplitTouch) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- // Create first non touch modal window that supports split touch
sp<FakeWindowHandle> firstWindow =
new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
firstWindow->setFrame(Rect(0, 0, 600, 400));
- firstWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
- // Create second non touch modal window that supports split touch
sp<FakeWindowHandle> secondWindow =
new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
secondWindow->setFrame(Rect(0, 400, 600, 800));
- secondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
// Add the windows to the dispatcher
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}});
@@ -3229,9 +3212,9 @@
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
+ window->setFocusable(false);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
- // Window is not focusable.
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
setFocusedWindow(window);
@@ -3239,7 +3222,7 @@
ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(mDispatcher))
<< "Inject key event should return InputEventInjectionResult::TIMED_OUT";
- // window is invalid, so it should not receive any input event.
+ // window is not focusable, so it should not receive any input event.
window->assertNoEvents();
}
@@ -3376,7 +3359,7 @@
sp<FakeWindowHandle> slipperyExitWindow =
new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
- slipperyExitWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SLIPPERY);
+ slipperyExitWindow->setSlippery(true);
// Make sure this one overlaps the bottom window
slipperyExitWindow->setFrame(Rect(25, 25, 75, 75));
// Change the owner uid/pid of the window so that it is considered to be occluding the bottom
@@ -3982,14 +3965,10 @@
mUnfocusedWindow =
new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
- // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this
- // window.
- mUnfocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
mFocusedWindow =
new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
- mFocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
// Set focused application.
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -4096,14 +4075,10 @@
std::make_shared<FakeApplicationHandle>();
mWindow1 = new FakeWindowHandle(application, mDispatcher, "Fake Window 1",
ADISPLAY_ID_DEFAULT);
- // Adding FLAG_NOT_TOUCH_MODAL otherwise all taps will go to the top most window.
- // We also need FLAG_SPLIT_TOUCH or we won't be able to get touches for both windows.
- mWindow1->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
mWindow1->setFrame(Rect(0, 0, 100, 100));
mWindow2 = new FakeWindowHandle(application, mDispatcher, "Fake Window 2",
ADISPLAY_ID_DEFAULT, mWindow1->getToken());
- mWindow2->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
mWindow2->setFrame(Rect(100, 100, 200, 200));
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow1, mWindow2}}});
@@ -4300,9 +4275,6 @@
mWindow->setFrame(Rect(0, 0, 30, 30));
mWindow->setDispatchingTimeout(30ms);
mWindow->setFocusable(true);
- // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this
- // window.
- mWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
// Set focused application.
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
@@ -4750,18 +4722,13 @@
mUnfocusedWindow =
new FakeWindowHandle(mApplication, mDispatcher, "Unfocused", ADISPLAY_ID_DEFAULT);
mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
- // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this
- // window.
// Adding FLAG_WATCH_OUTSIDE_TOUCH to receive ACTION_OUTSIDE when another window is tapped
- mUnfocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL |
- WindowInfo::Flag::WATCH_OUTSIDE_TOUCH |
- WindowInfo::Flag::SPLIT_TOUCH);
+ mUnfocusedWindow->setWatchOutsideTouch(true);
mFocusedWindow =
new FakeWindowHandle(mApplication, mDispatcher, "Focused", ADISPLAY_ID_DEFAULT);
mFocusedWindow->setDispatchingTimeout(30ms);
mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
- mFocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
// Set focused application.
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
@@ -5495,7 +5462,7 @@
sp<FakeWindowHandle> getOccludingWindow(int32_t uid, std::string name, TouchOcclusionMode mode,
float alpha = 1.0f) {
sp<FakeWindowHandle> window = getWindow(uid, name);
- window->setFlags(WindowInfo::Flag::NOT_TOUCHABLE);
+ window->setTouchable(false);
window->setTouchOcclusionMode(mode);
window->setAlpha(alpha);
return window;
@@ -5609,7 +5576,7 @@
WindowWithZeroOpacityAndWatchOutside_ReceivesOutsideEvent) {
const sp<FakeWindowHandle>& w =
getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
- w->addFlags(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH);
+ w->setWatchOutsideTouch(true);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
touch();
@@ -5620,7 +5587,7 @@
TEST_F(InputDispatcherUntrustedTouchesTest, OutsideEvent_HasZeroCoordinates) {
const sp<FakeWindowHandle>& w =
getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
- w->addFlags(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH);
+ w->setWatchOutsideTouch(true);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
touch();
@@ -5870,11 +5837,9 @@
mApp = std::make_shared<FakeApplicationHandle>();
mWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
mWindow->setFrame(Rect(0, 0, 100, 100));
- mWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
mSecondWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
mSecondWindow->setFrame(Rect(100, 0, 200, 100));
- mSecondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}});
@@ -6129,7 +6094,7 @@
ADISPLAY_ID_DEFAULT);
obscuringWindow->setFrame(Rect(0, 0, 50, 50));
obscuringWindow->setOwnerInfo(111, 111);
- obscuringWindow->setFlags(WindowInfo::Flag::NOT_TOUCHABLE);
+ obscuringWindow->setTouchable(false);
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
@@ -6175,7 +6140,7 @@
ADISPLAY_ID_DEFAULT);
obscuringWindow->setFrame(Rect(0, 0, 50, 50));
obscuringWindow->setOwnerInfo(111, 111);
- obscuringWindow->setFlags(WindowInfo::Flag::NOT_TOUCHABLE);
+ obscuringWindow->setTouchable(false);
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
@@ -6224,40 +6189,64 @@
mApp = std::make_shared<FakeApplicationHandle>();
mWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
mWindow->setFocusable(true);
+ setFocusedWindow(mWindow);
mSecondWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
mSecondWindow->setFocusable(true);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}});
-
- setFocusedWindow(mWindow);
mWindow->consumeFocusEvent(true);
+
+ // Set initial touch mode to InputDispatcher::kDefaultInTouchMode.
+ mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, INJECTOR_PID,
+ INJECTOR_UID, /* hasPermission */ true);
}
void changeAndVerifyTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission) {
- mDispatcher->setInTouchMode(inTouchMode, pid, uid, hasPermission);
+ ASSERT_TRUE(mDispatcher->setInTouchMode(inTouchMode, pid, uid, hasPermission));
mWindow->consumeTouchModeEvent(inTouchMode);
mSecondWindow->consumeTouchModeEvent(inTouchMode);
}
};
-TEST_F(InputDispatcherTouchModeChangedTests, ChangeTouchModeOnFocusedWindow) {
+TEST_F(InputDispatcherTouchModeChangedTests, FocusedWindowCanChangeTouchMode) {
const WindowInfo& windowInfo = *mWindow->getInfo();
changeAndVerifyTouchMode(!InputDispatcher::kDefaultInTouchMode, windowInfo.ownerPid,
windowInfo.ownerUid, /* hasPermission */ false);
}
+TEST_F(InputDispatcherTouchModeChangedTests, NonFocusedWindowOwnerCannotChangeTouchMode) {
+ const WindowInfo& windowInfo = *mWindow->getInfo();
+ int32_t ownerPid = windowInfo.ownerPid;
+ int32_t ownerUid = windowInfo.ownerUid;
+ mWindow->setOwnerInfo(/* pid */ -1, /* uid */ -1);
+ ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, ownerPid,
+ ownerUid, /* hasPermission */ false));
+ mWindow->assertNoEvents();
+ mSecondWindow->assertNoEvents();
+}
+
+TEST_F(InputDispatcherTouchModeChangedTests, NonWindowOwnerMayChangeTouchModeOnPermissionGranted) {
+ const WindowInfo& windowInfo = *mWindow->getInfo();
+ int32_t ownerPid = windowInfo.ownerPid;
+ int32_t ownerUid = windowInfo.ownerUid;
+ mWindow->setOwnerInfo(/* pid */ -1, /* uid */ -1);
+ changeAndVerifyTouchMode(!InputDispatcher::kDefaultInTouchMode, ownerPid, ownerUid,
+ /* hasPermission */ true);
+}
+
TEST_F(InputDispatcherTouchModeChangedTests, EventIsNotGeneratedIfNotChangingTouchMode) {
const WindowInfo& windowInfo = *mWindow->getInfo();
- mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, windowInfo.ownerPid,
- windowInfo.ownerUid, /* hasPermission */ true);
+ ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode,
+ windowInfo.ownerPid, windowInfo.ownerUid,
+ /* hasPermission */ true));
mWindow->assertNoEvents();
mSecondWindow->assertNoEvents();
}
class InputDispatcherSpyWindowTest : public InputDispatcherTest {
public:
- sp<FakeWindowHandle> createSpy(const Flags<WindowInfo::Flag> flags) {
+ sp<FakeWindowHandle> createSpy() {
std::shared_ptr<FakeApplicationHandle> application =
std::make_shared<FakeApplicationHandle>();
std::string name = "Fake Spy ";
@@ -6266,7 +6255,6 @@
new FakeWindowHandle(application, mDispatcher, name.c_str(), ADISPLAY_ID_DEFAULT);
spy->setInputFeatures(WindowInfo::Feature::SPY);
spy->setTrustedOverlay(true);
- spy->addFlags(flags);
return spy;
}
@@ -6275,7 +6263,6 @@
std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
- window->addFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
window->setFocusable(true);
return window;
}
@@ -6291,7 +6278,7 @@
TEST_F(InputDispatcherSpyWindowDeathTest, UntrustedSpy_AbortsDispatcher) {
ScopedSilentDeath _silentDeath;
- auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ auto spy = createSpy();
spy->setTrustedOverlay(false);
ASSERT_DEATH(mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy}}}),
".* not a trusted overlay");
@@ -6301,7 +6288,7 @@
* Input injection into a display with a spy window but no foreground windows should succeed.
*/
TEST_F(InputDispatcherSpyWindowTest, NoForegroundWindow) {
- auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ auto spy = createSpy();
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy}}});
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -6324,14 +6311,14 @@
*/
TEST_F(InputDispatcherSpyWindowTest, ReceivesInputInOrder) {
auto window = createForeground();
- auto spy1 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
- auto spy2 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
- auto spy3 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ auto spy1 = createSpy();
+ auto spy2 = createSpy();
+ auto spy3 = createSpy();
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy1, spy2, window, spy3}}});
const std::vector<sp<FakeWindowHandle>> channels{spy1, spy2, window, spy3};
const size_t numChannels = channels.size();
- base::unique_fd epollFd(epoll_create1(0 /*flags*/));
+ base::unique_fd epollFd(epoll_create1(EPOLL_CLOEXEC));
if (!epollFd.ok()) {
FAIL() << "Failed to create epoll fd";
}
@@ -6377,7 +6364,8 @@
*/
TEST_F(InputDispatcherSpyWindowTest, NotTouchable) {
auto window = createForeground();
- auto spy = createSpy(WindowInfo::Flag::NOT_TOUCHABLE);
+ auto spy = createSpy();
+ spy->setTouchable(false);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -6394,7 +6382,7 @@
*/
TEST_F(InputDispatcherSpyWindowTest, TouchableRegion) {
auto window = createForeground();
- auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ auto spy = createSpy();
spy->setTouchableRegion(Region{{0, 0, 20, 20}});
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
@@ -6420,32 +6408,14 @@
}
/**
- * A spy window that is a modal window will receive gestures outside of its frame and touchable
- * region.
- */
-TEST_F(InputDispatcherSpyWindowTest, ModalWindow) {
- auto window = createForeground();
- auto spy = createSpy(static_cast<WindowInfo::Flag>(0));
- // This spy window does not have the NOT_TOUCH_MODAL flag set.
- spy->setFrame(Rect{0, 0, 20, 20});
- mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
-
- // Inject an event outside the spy window's frame and touchable region.
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
- << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
- window->consumeMotionDown();
- spy->consumeMotionDown();
-}
-
-/**
* A spy window can listen for touches outside its touchable region using the WATCH_OUTSIDE_TOUCHES
* flag, but it will get zero-ed out coordinates if the foreground has a different owner.
*/
TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) {
auto window = createForeground();
window->setOwnerInfo(12, 34);
- auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::WATCH_OUTSIDE_TOUCH);
+ auto spy = createSpy();
+ spy->setWatchOutsideTouch(true);
spy->setOwnerInfo(56, 78);
spy->setFrame(Rect{0, 0, 20, 20});
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
@@ -6465,8 +6435,8 @@
*/
TEST_F(InputDispatcherSpyWindowTest, PilferPointers) {
auto window = createForeground();
- auto spy1 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
- auto spy2 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ auto spy1 = createSpy();
+ auto spy2 = createSpy();
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy1, spy2, window}}});
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -6498,7 +6468,7 @@
*/
TEST_F(InputDispatcherSpyWindowTest, CanPilferAfterWindowIsRemovedMidStream) {
auto window = createForeground();
- auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ auto spy = createSpy();
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -6522,9 +6492,8 @@
* the spy, but not to any other windows.
*/
TEST_F(InputDispatcherSpyWindowTest, ContinuesToReceiveGestureAfterPilfer) {
- auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
+ auto spy = createSpy();
auto window = createForeground();
- window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
@@ -6590,7 +6559,7 @@
windowLeft->setFrame({0, 0, 100, 200});
auto windowRight = createForeground();
windowRight->setFrame({100, 0, 200, 200});
- auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ auto spy = createSpy();
spy->setFrame({0, 0, 200, 200});
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, windowLeft, windowRight}}});
@@ -6625,7 +6594,7 @@
TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) {
auto window = createForeground();
window->setFrame({0, 0, 200, 200});
- auto spyRight = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ auto spyRight = createSpy();
spyRight->setFrame({100, 0, 200, 200});
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyRight, window}}});
@@ -6658,15 +6627,13 @@
* windows should be allowed to control split touch.
*/
TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) {
- // Create a touch modal spy that spies on the entire display.
- // This spy window does not set the SPLIT_TOUCH flag. However, we still expect to split touches
+ // This spy window prevents touch splitting. However, we still expect to split touches
// because a foreground window has not disabled splitting.
- auto spy = createSpy(static_cast<WindowInfo::Flag>(0));
+ auto spy = createSpy();
+ spy->setPreventSplitting(true);
- // Create a non touch modal window that supports split touch.
auto window = createForeground();
window->setFrame(Rect(0, 0, 100, 100));
- window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
@@ -6704,7 +6671,7 @@
* do not receive key events.
*/
TEST_F(InputDispatcherSpyWindowTest, UnfocusableSpyDoesNotReceiveKeyEvents) {
- auto spy = createSpy(static_cast<WindowInfo::Flag>(0));
+ auto spy = createSpy();
spy->setFocusable(false);
auto window = createForeground();
@@ -6733,7 +6700,7 @@
ADISPLAY_ID_DEFAULT);
overlay->setFocusable(false);
overlay->setOwnerInfo(111, 111);
- overlay->setFlags(WindowInfo::Flag::NOT_TOUCHABLE | WindowInfo::Flag::SPLIT_TOUCH);
+ overlay->setTouchable(false);
overlay->setInputFeatures(WindowInfo::Feature::INTERCEPTS_STYLUS);
overlay->setTrustedOverlay(true);
@@ -6744,7 +6711,6 @@
ADISPLAY_ID_DEFAULT);
window->setFocusable(true);
window->setOwnerInfo(222, 222);
- window->setFlags(WindowInfo::Flag::SPLIT_TOUCH);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}});
@@ -6820,7 +6786,4 @@
window->assertNoEvents();
}
-// TODO(b/198487159): Add permission tests for touch mode switch once the validation is put in
-// place.
-
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/tests/UinputDevice.cpp b/services/inputflinger/tests/UinputDevice.cpp
index 132b877..9c93919 100644
--- a/services/inputflinger/tests/UinputDevice.cpp
+++ b/services/inputflinger/tests/UinputDevice.cpp
@@ -17,6 +17,7 @@
#include "UinputDevice.h"
#include <android-base/stringprintf.h>
+#include <fcntl.h>
namespace android {
@@ -32,7 +33,7 @@
}
void UinputDevice::init() {
- mDeviceFd = android::base::unique_fd(open("/dev/uinput", O_WRONLY | O_NONBLOCK));
+ mDeviceFd = android::base::unique_fd(open("/dev/uinput", O_WRONLY | O_NONBLOCK | O_CLOEXEC));
if (mDeviceFd < 0) {
FAIL() << "Can't open /dev/uinput :" << strerror(errno);
}
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 971491d..3c164aa 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -134,6 +134,7 @@
mWakeLockAcquired(false), mLastReportedProxIsActive(false) {
mUidPolicy = new UidPolicy(this);
mSensorPrivacyPolicy = new SensorPrivacyPolicy(this);
+ mMicSensorPrivacyPolicy = new MicrophonePrivacyPolicy(this);
}
bool SensorService::initializeHmacKey() {
@@ -369,6 +370,9 @@
// Start watching sensor privacy changes
mSensorPrivacyPolicy->registerSelf();
+
+ // Start watching mic sensor privacy changes
+ mMicSensorPrivacyPolicy->registerSelf();
}
}
}
@@ -439,9 +443,7 @@
}
mUidPolicy->unregisterSelf();
mSensorPrivacyPolicy->unregisterSelf();
- for (auto const& [userId, policy] : mMicSensorPrivacyPolicies) {
- policy->unregisterSelf();
- }
+ mMicSensorPrivacyPolicy->unregisterSelf();
}
status_t SensorService::dump(int fd, const Vector<String16>& args) {
@@ -773,33 +775,25 @@
checkAndReportProxStateChangeLocked();
}
-void SensorService::capRates(userid_t userId) {
+void SensorService::capRates() {
ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
for (const sp<SensorDirectConnection>& conn : connLock.getDirectConnections()) {
- if (conn->getUserId() == userId) {
- conn->onMicSensorAccessChanged(true);
- }
+ conn->onMicSensorAccessChanged(true);
}
for (const sp<SensorEventConnection>& conn : connLock.getActiveConnections()) {
- if (conn->getUserId() == userId) {
- conn->onMicSensorAccessChanged(true);
- }
+ conn->onMicSensorAccessChanged(true);
}
}
-void SensorService::uncapRates(userid_t userId) {
+void SensorService::uncapRates() {
ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
for (const sp<SensorDirectConnection>& conn : connLock.getDirectConnections()) {
- if (conn->getUserId() == userId) {
- conn->onMicSensorAccessChanged(false);
- }
+ conn->onMicSensorAccessChanged(false);
}
for (const sp<SensorEventConnection>& conn : connLock.getActiveConnections()) {
- if (conn->getUserId() == userId) {
- conn->onMicSensorAccessChanged(false);
- }
+ conn->onMicSensorAccessChanged(false);
}
}
@@ -2243,7 +2237,6 @@
status_t SensorService::adjustSamplingPeriodBasedOnMicAndPermission(nsecs_t* requestedPeriodNs,
const String16& opPackageName) {
- uid_t uid = IPCThreadState::self()->getCallingUid();
if (*requestedPeriodNs >= SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS) {
return OK;
}
@@ -2255,7 +2248,7 @@
}
return OK;
}
- if (isMicSensorPrivacyEnabledForUid(uid)) {
+ if (mMicSensorPrivacyPolicy->isSensorPrivacyEnabled()) {
*requestedPeriodNs = SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS;
return OK;
}
@@ -2264,7 +2257,6 @@
status_t SensorService::adjustRateLevelBasedOnMicAndPermission(int* requestedRateLevel,
const String16& opPackageName) {
- uid_t uid = IPCThreadState::self()->getCallingUid();
if (*requestedRateLevel <= SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL) {
return OK;
}
@@ -2276,7 +2268,7 @@
}
return OK;
}
- if (isMicSensorPrivacyEnabledForUid(uid)) {
+ if (mMicSensorPrivacyPolicy->isSensorPrivacyEnabled()) {
*requestedRateLevel = SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL;
return OK;
}
@@ -2293,69 +2285,63 @@
void SensorService::SensorPrivacyPolicy::unregisterSelf() {
AutoCallerClear acc;
SensorPrivacyManager spm;
- if (mIsIndividualMic) {
- spm.removeIndividualSensorPrivacyListener(
- SensorPrivacyManager::INDIVIDUAL_SENSOR_MICROPHONE, this);
- } else {
- spm.removeSensorPrivacyListener(this);
- }
+ spm.removeSensorPrivacyListener(this);
}
bool SensorService::SensorPrivacyPolicy::isSensorPrivacyEnabled() {
return mSensorPrivacyEnabled;
}
-binder::Status SensorService::SensorPrivacyPolicy::onSensorPrivacyChanged(bool enabled) {
+binder::Status SensorService::SensorPrivacyPolicy::onSensorPrivacyChanged(int toggleType __unused,
+ int sensor __unused, bool enabled) {
mSensorPrivacyEnabled = enabled;
sp<SensorService> service = mService.promote();
if (service != nullptr) {
- if (mIsIndividualMic) {
- if (enabled) {
- service->capRates(mUserId);
- } else {
- service->uncapRates(mUserId);
- }
+ if (enabled) {
+ service->disableAllSensors();
} else {
- if (enabled) {
- service->disableAllSensors();
- } else {
- service->enableAllSensors();
- }
+ service->enableAllSensors();
}
}
return binder::Status::ok();
}
-status_t SensorService::SensorPrivacyPolicy::registerSelfForIndividual(int userId) {
- Mutex::Autolock _l(mSensorPrivacyLock);
+void SensorService::MicrophonePrivacyPolicy::registerSelf() {
AutoCallerClear acc;
SensorPrivacyManager spm;
- status_t err = spm.addIndividualSensorPrivacyListener(userId,
- SensorPrivacyManager::INDIVIDUAL_SENSOR_MICROPHONE, this);
-
- if (err != OK) {
- ALOGE("Cannot register a mic listener.");
- return err;
- }
- mSensorPrivacyEnabled = spm.isIndividualSensorPrivacyEnabled(userId,
- SensorPrivacyManager::INDIVIDUAL_SENSOR_MICROPHONE);
-
- mIsIndividualMic = true;
- mUserId = userId;
- return OK;
+ mSensorPrivacyEnabled =
+ spm.isToggleSensorPrivacyEnabled(
+ SensorPrivacyManager::TOGGLE_TYPE_SOFTWARE,
+ SensorPrivacyManager::TOGGLE_SENSOR_MICROPHONE)
+ || spm.isToggleSensorPrivacyEnabled(
+ SensorPrivacyManager::TOGGLE_TYPE_HARDWARE,
+ SensorPrivacyManager::TOGGLE_SENSOR_MICROPHONE);
+ spm.addToggleSensorPrivacyListener(this);
}
-bool SensorService::isMicSensorPrivacyEnabledForUid(uid_t uid) {
- userid_t userId = multiuser_get_user_id(uid);
- if (mMicSensorPrivacyPolicies.find(userId) == mMicSensorPrivacyPolicies.end()) {
- sp<SensorPrivacyPolicy> userPolicy = new SensorPrivacyPolicy(this);
- if (userPolicy->registerSelfForIndividual(userId) != OK) {
- return false;
- }
- mMicSensorPrivacyPolicies[userId] = userPolicy;
+void SensorService::MicrophonePrivacyPolicy::unregisterSelf() {
+ AutoCallerClear acc;
+ SensorPrivacyManager spm;
+ spm.removeToggleSensorPrivacyListener(this);
+}
+
+binder::Status SensorService::MicrophonePrivacyPolicy::onSensorPrivacyChanged(int toggleType __unused,
+ int sensor, bool enabled) {
+ if (sensor != SensorPrivacyManager::TOGGLE_SENSOR_MICROPHONE) {
+ return binder::Status::ok();
}
- return mMicSensorPrivacyPolicies[userId]->isSensorPrivacyEnabled();
+ mSensorPrivacyEnabled = enabled;
+ sp<SensorService> service = mService.promote();
+
+ if (service != nullptr) {
+ if (enabled) {
+ service->capRates();
+ } else {
+ service->uncapRates();
+ }
+ }
+ return binder::Status::ok();
}
SensorService::ConnectionSafeAutolock::ConnectionSafeAutolock(
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index b009829..7194db3 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -289,22 +289,32 @@
class SensorPrivacyPolicy : public hardware::BnSensorPrivacyListener {
public:
explicit SensorPrivacyPolicy(wp<SensorService> service)
- : mService(service), mIsIndividualMic(false), mUserId(0) {}
+ : mService(service) {}
void registerSelf();
void unregisterSelf();
- status_t registerSelfForIndividual(int userId);
-
bool isSensorPrivacyEnabled();
- binder::Status onSensorPrivacyChanged(bool enabled);
+ binder::Status onSensorPrivacyChanged(int toggleType, int sensor,
+ bool enabled);
+
+ protected:
+ std::atomic_bool mSensorPrivacyEnabled;
+ wp<SensorService> mService;
private:
- wp<SensorService> mService;
Mutex mSensorPrivacyLock;
- std::atomic_bool mSensorPrivacyEnabled;
- bool mIsIndividualMic;
- userid_t mUserId;
+ };
+
+ class MicrophonePrivacyPolicy : public SensorPrivacyPolicy {
+ public:
+ explicit MicrophonePrivacyPolicy(wp<SensorService> service)
+ : SensorPrivacyPolicy(service) {}
+ void registerSelf();
+ void unregisterSelf();
+
+ binder::Status onSensorPrivacyChanged(int toggleType, int sensor,
+ bool enabled);
};
// A class automatically clearing and restoring binder caller identity inside
@@ -444,9 +454,9 @@
void enableAllSensorsLocked(ConnectionSafeAutolock* connLock);
// Caps active direct connections (when the mic toggle is flipped to on)
- void capRates(userid_t userId);
+ void capRates();
// Removes the capped rate on active direct connections (when the mic toggle is flipped to off)
- void uncapRates(userid_t userId);
+ void uncapRates();
static inline bool isAudioServerOrSystemServerUid(uid_t uid) {
return multiuser_get_app_id(uid) == AID_SYSTEM || uid == AID_AUDIOSERVER;
@@ -497,10 +507,7 @@
static Mutex sPackageTargetVersionLock;
static String16 sSensorInterfaceDescriptorPrefix;
- // Map from user to SensorPrivacyPolicy
- std::map<userid_t, sp<SensorPrivacyPolicy>> mMicSensorPrivacyPolicies;
- // Checks if the mic sensor privacy is enabled for the uid
- bool isMicSensorPrivacyEnabledForUid(uid_t uid);
+ sp<MicrophonePrivacyPolicy> mMicSensorPrivacyPolicy;
// Keeps track of the handles of all proximity sensors in the system.
std::vector<int32_t> mProxSensorHandles;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 40fc342..02e444d 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -416,8 +416,14 @@
? bufferData.acquireFence
: Fence::NO_FENCE;
mDrawingState.acquireFenceTime = std::make_unique<FenceTime>(mDrawingState.acquireFence);
- // The acquire fences of BufferStateLayers have already signaled before they are set
- mCallbackHandleAcquireTime = mDrawingState.acquireFenceTime->getSignalTime();
+ if (mDrawingState.acquireFenceTime->getSignalTime() == Fence::SIGNAL_TIME_PENDING) {
+ // We latched this buffer unsiganled, so we need to pass the acquire fence
+ // on the callback instead of just the acquire time, since it's unknown at
+ // this point.
+ mCallbackHandleAcquireTimeOrFence = mDrawingState.acquireFence;
+ } else {
+ mCallbackHandleAcquireTimeOrFence = mDrawingState.acquireFenceTime->getSignalTime();
+ }
mDrawingState.modified = true;
setTransactionFlags(eTransactionNeeded);
@@ -527,7 +533,7 @@
// If this layer will be presented in this frame
if (willPresent) {
// If this transaction set an acquire fence on this layer, set its acquire time
- handle->acquireTime = mCallbackHandleAcquireTime;
+ handle->acquireTimeOrFence = mCallbackHandleAcquireTimeOrFence;
handle->frameNumber = mDrawingState.frameNumber;
// Store so latched time and release fence can be set
@@ -540,7 +546,7 @@
}
mReleasePreviousBuffer = false;
- mCallbackHandleAcquireTime = -1;
+ mCallbackHandleAcquireTimeOrFence = -1;
return willPresent;
}
@@ -918,4 +924,183 @@
return mDrawingState.transform.transform(bufferBounds);
}
+bool BufferStateLayer::simpleBufferUpdate(const layer_state_t& s) const {
+ const uint64_t requiredFlags = layer_state_t::eBufferChanged;
+
+ const uint64_t deniedFlags = layer_state_t::eProducerDisconnect | layer_state_t::eLayerChanged |
+ layer_state_t::eRelativeLayerChanged | layer_state_t::eTransparentRegionChanged |
+ layer_state_t::eFlagsChanged | layer_state_t::eBlurRegionsChanged |
+ layer_state_t::eLayerStackChanged | layer_state_t::eAutoRefreshChanged |
+ layer_state_t::eReparent;
+
+ const uint64_t allowedFlags = layer_state_t::eHasListenerCallbacksChanged |
+ layer_state_t::eFrameRateSelectionPriority | layer_state_t::eFrameRateChanged |
+ layer_state_t::eSurfaceDamageRegionChanged | layer_state_t::eApiChanged |
+ layer_state_t::eMetadataChanged | layer_state_t::eDropInputModeChanged |
+ layer_state_t::eInputInfoChanged;
+
+ if ((s.what & requiredFlags) != requiredFlags) {
+ ALOGV("%s: false [missing required flags 0x%" PRIx64 "]", __func__,
+ (s.what | requiredFlags) & ~s.what);
+ return false;
+ }
+
+ if (s.what & deniedFlags) {
+ ALOGV("%s: false [has denied flags 0x%" PRIx64 "]", __func__, s.what & deniedFlags);
+ return false;
+ }
+
+ if (s.what & allowedFlags) {
+ ALOGV("%s: [has allowed flags 0x%" PRIx64 "]", __func__, s.what & allowedFlags);
+ }
+
+ if (s.what & layer_state_t::ePositionChanged) {
+ if (mRequestedTransform.tx() != s.x || mRequestedTransform.ty() != s.y) {
+ ALOGV("%s: false [ePositionChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eAlphaChanged) {
+ if (mDrawingState.color.a != s.alpha) {
+ ALOGV("%s: false [eAlphaChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eColorTransformChanged) {
+ if (mDrawingState.colorTransform != s.colorTransform) {
+ ALOGV("%s: false [eColorTransformChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eBackgroundColorChanged) {
+ if (mDrawingState.bgColorLayer || s.bgColorAlpha != 0) {
+ ALOGV("%s: false [eBackgroundColorChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eMatrixChanged) {
+ if (mRequestedTransform.dsdx() != s.matrix.dsdx ||
+ mRequestedTransform.dtdy() != s.matrix.dtdy ||
+ mRequestedTransform.dtdx() != s.matrix.dtdx ||
+ mRequestedTransform.dsdy() != s.matrix.dsdy) {
+ ALOGV("%s: false [eMatrixChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eCornerRadiusChanged) {
+ if (mDrawingState.cornerRadius != s.cornerRadius) {
+ ALOGV("%s: false [eCornerRadiusChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eBackgroundBlurRadiusChanged) {
+ if (mDrawingState.backgroundBlurRadius != static_cast<int>(s.backgroundBlurRadius)) {
+ ALOGV("%s: false [eBackgroundBlurRadiusChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eTransformChanged) {
+ if (mDrawingState.bufferTransform != s.transform) {
+ ALOGV("%s: false [eTransformChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eTransformToDisplayInverseChanged) {
+ if (mDrawingState.transformToDisplayInverse != s.transformToDisplayInverse) {
+ ALOGV("%s: false [eTransformToDisplayInverseChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eCropChanged) {
+ if (mDrawingState.crop != s.crop) {
+ ALOGV("%s: false [eCropChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eDataspaceChanged) {
+ if (mDrawingState.dataspace != s.dataspace) {
+ ALOGV("%s: false [eDataspaceChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eHdrMetadataChanged) {
+ if (mDrawingState.hdrMetadata != s.hdrMetadata) {
+ ALOGV("%s: false [eHdrMetadataChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eSidebandStreamChanged) {
+ if (mDrawingState.sidebandStream != s.sidebandStream) {
+ ALOGV("%s: false [eSidebandStreamChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eColorSpaceAgnosticChanged) {
+ if (mDrawingState.colorSpaceAgnostic != s.colorSpaceAgnostic) {
+ ALOGV("%s: false [eColorSpaceAgnosticChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eShadowRadiusChanged) {
+ if (mDrawingState.shadowRadius != s.shadowRadius) {
+ ALOGV("%s: false [eShadowRadiusChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eFixedTransformHintChanged) {
+ if (mDrawingState.fixedTransformHint != s.fixedTransformHint) {
+ ALOGV("%s: false [eFixedTransformHintChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eTrustedOverlayChanged) {
+ if (mDrawingState.isTrustedOverlay != s.isTrustedOverlay) {
+ ALOGV("%s: false [eTrustedOverlayChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eStretchChanged) {
+ StretchEffect temp = s.stretchEffect;
+ temp.sanitize();
+ if (mDrawingState.stretchEffect != temp) {
+ ALOGV("%s: false [eStretchChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eBufferCropChanged) {
+ if (mDrawingState.bufferCrop != s.bufferCrop) {
+ ALOGV("%s: false [eBufferCropChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eDestinationFrameChanged) {
+ if (mDrawingState.destinationFrame != s.destinationFrame) {
+ ALOGV("%s: false [eDestinationFrameChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ ALOGV("%s: true", __func__);
+ return true;
+}
+
} // namespace android
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 248e013..669eaad 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -136,6 +136,8 @@
bool bufferNeedsFiltering() const override;
+ bool simpleBufferUpdate(const layer_state_t& s) const override;
+
ReleaseCallbackId mPreviousReleaseCallbackId = ReleaseCallbackId::INVALID_ID;
uint64_t mPreviousReleasedFrameNumber = 0;
@@ -143,7 +145,7 @@
// Stores the last set acquire fence signal time used to populate the callback handle's acquire
// time.
- nsecs_t mCallbackHandleAcquireTime = -1;
+ std::variant<nsecs_t, sp<Fence>> mCallbackHandleAcquireTimeOrFence = -1;
std::deque<std::shared_ptr<android::frametimeline::SurfaceFrame>> mPendingJankClassifications;
// An upper bound on the number of SurfaceFrames in the pending classifications deque.
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
index 08cfaa6..2b383c1 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
@@ -153,9 +153,11 @@
// Timestamp for when the layer is queued for client composition
nsecs_t clientCompositionTimestamp{0};
- // White point of the layer, in nits.
static constexpr float kDefaultWhitePointNits = 200.f;
float whitePointNits = kDefaultWhitePointNits;
+ // Dimming ratio of the layer from [0, 1]
+ static constexpr float kDefaultDimmingRatio = 1.f;
+ float dimmingRatio = kDefaultDimmingRatio;
};
} // namespace compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 29c146b..a3188f3 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -39,6 +39,7 @@
#include "DisplayHardware/PowerAdvisor.h"
+using aidl::android::hardware::graphics::composer3::Capability;
using aidl::android::hardware::graphics::composer3::DisplayCapability;
namespace android::compositionengine::impl {
@@ -284,7 +285,7 @@
DisplayCapability::SKIP_CLIENT_COLOR_TRANSFORM);
}
- return hwc.hasCapability(hal::Capability::SKIP_CLIENT_COLOR_TRANSFORM);
+ return hwc.hasCapability(Capability::SKIP_CLIENT_COLOR_TRANSFORM);
}
bool Display::anyLayersRequireClientComposition() const {
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 4ccf11f..3e983f3 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -324,9 +324,14 @@
// For hdr content, treat the white point as the display brightness - HDR content should not be
// boosted or dimmed.
- if (isHdrDataspace(state.dataspace)) {
+ if (isHdrDataspace(state.dataspace) ||
+ getOutput().getState().displayBrightnessNits == getOutput().getState().sdrWhitePointNits) {
+ state.dimmingRatio = 1.f;
state.whitePointNits = getOutput().getState().displayBrightnessNits;
} else {
+ state.dimmingRatio = std::clamp(getOutput().getState().sdrWhitePointNits /
+ getOutput().getState().displayBrightnessNits,
+ 0.f, 1.f);
state.whitePointNits = getOutput().getState().sdrWhitePointNits;
}
@@ -502,13 +507,12 @@
}
// Don't dim cached layers
- const auto whitePointNits = outputDependentState.overrideInfo.buffer
- ? getOutput().getState().displayBrightnessNits
- : outputDependentState.whitePointNits;
+ const auto dimmingRatio =
+ outputDependentState.overrideInfo.buffer ? 1.f : outputDependentState.dimmingRatio;
- if (auto error = hwcLayer->setWhitePointNits(whitePointNits); error != hal::Error::NONE) {
- ALOGE("[%s] Failed to set white point %f: %s (%d)", getLayerFE().getDebugName(),
- whitePointNits, to_string(error).c_str(), static_cast<int32_t>(error));
+ if (auto error = hwcLayer->setBrightness(dimmingRatio); error != hal::Error::NONE) {
+ ALOGE("[%s] Failed to set brightness %f: %s (%d)", getLayerFE().getDebugName(),
+ dimmingRatio, to_string(error).c_str(), static_cast<int32_t>(error));
}
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 125ce74..44d34a3 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -41,6 +41,7 @@
#include <aidl/android/hardware/graphics/composer3/Composition.h>
+using aidl::android::hardware::graphics::composer3::Capability;
using aidl::android::hardware::graphics::composer3::Composition;
namespace android::compositionengine {
@@ -672,7 +673,7 @@
using aidl::android::hardware::graphics::composer3::DisplayCapability;
TEST_F(DisplayGetSkipColorTransformTest, checksCapabilityIfGpuDisplay) {
- EXPECT_CALL(mHwComposer, hasCapability(hal::Capability::SKIP_CLIENT_COLOR_TRANSFORM))
+ EXPECT_CALL(mHwComposer, hasCapability(Capability::SKIP_CLIENT_COLOR_TRANSFORM))
.WillOnce(Return(true));
auto args = getDisplayCreationArgsForGpuVirtualDisplay();
auto gpuDisplay{impl::createDisplay(mCompositionEngine, args)};
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
index 5185ea9..d933b94 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
@@ -74,7 +74,7 @@
MOCK_METHOD1(setColorTransform, Error(const android::mat4&));
MOCK_METHOD3(setLayerGenericMetadata,
Error(const std::string&, bool, const std::vector<uint8_t>&));
- MOCK_METHOD1(setWhitePointNits, Error(float));
+ MOCK_METHOD1(setBrightness, Error(float));
MOCK_METHOD1(setBlockingRegion, Error(const android::Region&));
};
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 660f664..719f15c 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -42,7 +42,8 @@
MOCK_METHOD1(setCallback, void(HWC2::ComposerCallback&));
MOCK_CONST_METHOD3(getDisplayIdentificationData,
bool(hal::HWDisplayId, uint8_t*, DisplayIdentificationData*));
- MOCK_CONST_METHOD1(hasCapability, bool(hal::Capability));
+ MOCK_CONST_METHOD1(hasCapability,
+ bool(aidl::android::hardware::graphics::composer3::Capability));
MOCK_CONST_METHOD2(hasDisplayCapability,
bool(HalDisplayId,
aidl::android::hardware::graphics::composer3::DisplayCapability));
@@ -128,6 +129,10 @@
(const, override));
MOCK_METHOD(std::optional<hal::HWDisplayId>, fromPhysicalDisplayId, (PhysicalDisplayId),
(const, override));
+ MOCK_METHOD2(getDisplayDecorationSupport,
+ status_t(PhysicalDisplayId,
+ std::optional<aidl::android::hardware::graphics::common::
+ DisplayDecorationSupport>* support));
};
} // namespace mock
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 82dcc66..dda0822 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -751,6 +751,8 @@
static constexpr bool kLayerGenericMetadata2Mandatory = true;
static constexpr float kWhitePointNits = 200.f;
static constexpr float kDisplayBrightnessNits = 400.f;
+ static constexpr float kLayerBrightness = kWhitePointNits / kDisplayBrightnessNits;
+ static constexpr float kFullLayerBrightness = 1.f;
static const half4 kColor;
static const Rect kDisplayFrame;
@@ -782,6 +784,7 @@
outputLayerState.outputSpaceVisibleRegion = kOutputSpaceVisibleRegion;
outputLayerState.dataspace = kDataspace;
outputLayerState.whitePointNits = kWhitePointNits;
+ outputLayerState.dimmingRatio = kLayerBrightness;
mLayerFEState.blendMode = kBlendMode;
mLayerFEState.alpha = kAlpha;
@@ -846,11 +849,11 @@
ui::Dataspace dataspace = kDataspace,
const Region& visibleRegion = kOutputSpaceVisibleRegion,
const Region& surfaceDamage = kSurfaceDamage,
- float whitePointNits = kWhitePointNits,
+ float brightness = kLayerBrightness,
const Region& blockingRegion = Region()) {
EXPECT_CALL(*mHwcLayer, setVisibleRegion(RegionEq(visibleRegion))).WillOnce(Return(kError));
EXPECT_CALL(*mHwcLayer, setDataspace(dataspace)).WillOnce(Return(kError));
- EXPECT_CALL(*mHwcLayer, setWhitePointNits(whitePointNits)).WillOnce(Return(kError));
+ EXPECT_CALL(*mHwcLayer, setBrightness(brightness)).WillOnce(Return(kError));
EXPECT_CALL(*mHwcLayer, setColorTransform(kColorTransform))
.WillOnce(Return(unsupported == SimulateUnsupported::ColorTransform
? hal::Error::UNSUPPORTED
@@ -1114,7 +1117,7 @@
expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform,
kOverrideBlendMode, kSkipAlpha);
expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
- kOverrideSurfaceDamage, kDisplayBrightnessNits);
+ kOverrideSurfaceDamage, kFullLayerBrightness);
expectSetHdrMetadataAndBufferCalls();
expectSetCompositionTypeCall(Composition::DEVICE);
EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
@@ -1130,7 +1133,7 @@
expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform,
kOverrideBlendMode, kSkipAlpha);
expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
- kOverrideSurfaceDamage, kDisplayBrightnessNits);
+ kOverrideSurfaceDamage, kFullLayerBrightness);
expectSetHdrMetadataAndBufferCalls();
expectSetCompositionTypeCall(Composition::DEVICE);
EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
@@ -1146,7 +1149,7 @@
expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform,
kOverrideBlendMode, kOverrideAlpha);
expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
- kOverrideSurfaceDamage, kDisplayBrightnessNits);
+ kOverrideSurfaceDamage, kFullLayerBrightness);
expectSetHdrMetadataAndBufferCalls(kOverrideHwcSlot, kOverrideBuffer, kOverrideFence);
expectSetCompositionTypeCall(Composition::DEVICE);
EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
@@ -1162,7 +1165,7 @@
expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform,
kOverrideBlendMode, kOverrideAlpha);
expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
- kOverrideSurfaceDamage, kDisplayBrightnessNits);
+ kOverrideSurfaceDamage, kFullLayerBrightness);
expectSetHdrMetadataAndBufferCalls(kOverrideHwcSlot, kOverrideBuffer, kOverrideFence);
expectSetCompositionTypeCall(Composition::DEVICE);
EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
@@ -1288,7 +1291,7 @@
expectGeometryCommonCalls();
expectPerFrameCommonCalls(SimulateUnsupported::None, kDataspace, kOutputSpaceVisibleRegion,
- kSurfaceDamage, kWhitePointNits, blockingRegion);
+ kSurfaceDamage, kLayerBrightness, blockingRegion);
expectSetHdrMetadataAndBufferCalls();
EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
expectSetCompositionTypeCall(Composition::DISPLAY_DECORATION);
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index b1057c3..8d67954 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -251,14 +251,14 @@
}
}
-std::vector<IComposer::Capability> AidlComposer::getCapabilities() {
+std::vector<Capability> AidlComposer::getCapabilities() {
std::vector<Capability> capabilities;
const auto status = mAidlComposer->getCapabilities(&capabilities);
if (!status.isOk()) {
ALOGE("getCapabilities failed %s", status.getDescription().c_str());
return {};
}
- return translate<IComposer::Capability>(capabilities);
+ return capabilities;
}
std::string AidlComposer::dumpDebugInfo() {
@@ -1062,9 +1062,8 @@
return Error::NONE;
}
-Error AidlComposer::setLayerWhitePointNits(Display display, Layer layer, float whitePointNits) {
- mWriter.setLayerWhitePointNits(translate<int64_t>(display), translate<int64_t>(layer),
- whitePointNits);
+Error AidlComposer::setLayerBrightness(Display display, Layer layer, float brightness) {
+ mWriter.setLayerBrightness(translate<int64_t>(display), translate<int64_t>(layer), brightness);
return Error::NONE;
}
@@ -1074,5 +1073,17 @@
translate<AidlRect>(blocking));
return Error::NONE;
}
+
+Error AidlComposer::getDisplayDecorationSupport(Display display,
+ std::optional<DisplayDecorationSupport>* support) {
+ const auto status =
+ mAidlComposerClient->getDisplayDecorationSupport(translate<int64_t>(display), support);
+ if (!status.isOk()) {
+ ALOGE("getDisplayDecorationSupport failed %s", status.getDescription().c_str());
+ support->reset();
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+ return Error::NONE;
+}
} // namespace Hwc2
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
index 374a436..724c6c9 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
@@ -45,6 +45,7 @@
namespace android::Hwc2 {
+using aidl::android::hardware::graphics::common::DisplayDecorationSupport;
using aidl::android::hardware::graphics::composer3::ComposerClientReader;
using aidl::android::hardware::graphics::composer3::ComposerClientWriter;
@@ -60,7 +61,8 @@
bool isSupported(OptionalFeature) const;
- std::vector<IComposer::Capability> getCapabilities() override;
+ std::vector<aidl::android::hardware::graphics::composer3::Capability> getCapabilities()
+ override;
std::string dumpDebugInfo() override;
void registerCallback(HWC2::ComposerCallback& callback) override;
@@ -210,12 +212,14 @@
float* outClientTargetWhitePointNits) override;
// AIDL Composer HAL
- Error setLayerWhitePointNits(Display display, Layer layer, float whitePointNits) override;
+ Error setLayerBrightness(Display display, Layer layer, float brightness) override;
Error setLayerBlockingRegion(Display display, Layer layer,
const std::vector<IComposerClient::Rect>& blocking) override;
Error setBootDisplayConfig(Display displayId, Config) override;
Error clearBootDisplayConfig(Display displayId) override;
Error getPreferredBootDisplayConfig(Display displayId, Config*) override;
+ Error getDisplayDecorationSupport(Display display,
+ std::optional<DisplayDecorationSupport>* support) override;
private:
// Many public functions above simply write a command into the command
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index fe55e6b..06aaa11 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -31,11 +31,15 @@
#include <ui/GraphicBuffer.h>
#include <utils/StrongPointer.h>
+#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
+#include <aidl/android/hardware/graphics/composer3/Capability.h>
#include <aidl/android/hardware/graphics/composer3/Color.h>
#include <aidl/android/hardware/graphics/composer3/Composition.h>
#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
#include <aidl/android/hardware/graphics/composer3/IComposerCallback.h>
+#include <optional>
+
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
@@ -93,7 +97,8 @@
virtual bool isSupported(OptionalFeature) const = 0;
- virtual std::vector<IComposer::Capability> getCapabilities() = 0;
+ virtual std::vector<aidl::android::hardware::graphics::composer3::Capability>
+ getCapabilities() = 0;
virtual std::string dumpDebugInfo() = 0;
virtual void registerCallback(HWC2::ComposerCallback& callback) = 0;
@@ -259,12 +264,16 @@
float* outWhitePointNits) = 0;
// AIDL Composer
- virtual Error setLayerWhitePointNits(Display display, Layer layer, float whitePointNits) = 0;
+ virtual Error setLayerBrightness(Display display, Layer layer, float brightness) = 0;
virtual Error setLayerBlockingRegion(Display display, Layer layer,
const std::vector<IComposerClient::Rect>& blocking) = 0;
virtual Error setBootDisplayConfig(Display displayId, Config) = 0;
virtual Error clearBootDisplayConfig(Display displayId) = 0;
virtual Error getPreferredBootDisplayConfig(Display displayId, Config*) = 0;
+ virtual Error getDisplayDecorationSupport(
+ Display display,
+ std::optional<::aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
+ support) = 0;
};
} // namespace Hwc2
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 05e3aef..a1b663c 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -39,6 +39,7 @@
using aidl::android::hardware::graphics::composer3::Color;
using aidl::android::hardware::graphics::composer3::Composition;
+using AidlCapability = aidl::android::hardware::graphics::composer3::Capability;
using aidl::android::hardware::graphics::composer3::DisplayCapability;
namespace android {
@@ -73,7 +74,7 @@
namespace impl {
Display::Display(android::Hwc2::Composer& composer,
- const std::unordered_set<Capability>& capabilities, HWDisplayId id,
+ const std::unordered_set<AidlCapability>& capabilities, HWDisplayId id,
DisplayType type)
: mComposer(composer), mCapabilities(capabilities), mId(id), mType(type) {
ALOGV("Created display %" PRIu64, id);
@@ -470,7 +471,7 @@
} else if (error == Error::UNSUPPORTED) {
std::scoped_lock lock(mDisplayCapabilitiesMutex);
mDisplayCapabilities.emplace();
- if (mCapabilities.count(Capability::SKIP_CLIENT_COLOR_TRANSFORM)) {
+ if (mCapabilities.count(AidlCapability::SKIP_CLIENT_COLOR_TRANSFORM)) {
mDisplayCapabilities->emplace(DisplayCapability::SKIP_CLIENT_COLOR_TRANSFORM);
}
bool dozeSupport = false;
@@ -580,6 +581,13 @@
return static_cast<Error>(error);
}
+Error Display::getDisplayDecorationSupport(
+ std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
+ support) {
+ const auto error = mComposer.getDisplayDecorationSupport(mId, support);
+ return static_cast<Error>(error);
+}
+
// For use by Device
void Display::setConnected(bool connected) {
@@ -618,8 +626,9 @@
namespace impl {
-Layer::Layer(android::Hwc2::Composer& composer, const std::unordered_set<Capability>& capabilities,
- HWC2::Display& display, HWLayerId layerId)
+Layer::Layer(android::Hwc2::Composer& composer,
+ const std::unordered_set<AidlCapability>& capabilities, HWC2::Display& display,
+ HWLayerId layerId)
: mComposer(composer),
mCapabilities(capabilities),
mDisplay(&display),
@@ -849,7 +858,7 @@
return Error::BAD_DISPLAY;
}
- if (mCapabilities.count(Capability::SIDEBAND_STREAM) == 0) {
+ if (mCapabilities.count(AidlCapability::SIDEBAND_STREAM) == 0) {
ALOGE("Attempted to call setSidebandStream without checking that the "
"device supports sideband streams");
return Error::UNSUPPORTED;
@@ -938,12 +947,12 @@
}
// AIDL HAL
-Error Layer::setWhitePointNits(float whitePointNits) {
+Error Layer::setBrightness(float brightness) {
if (CC_UNLIKELY(!mDisplay)) {
return Error::BAD_DISPLAY;
}
- auto intError = mComposer.setLayerWhitePointNits(mDisplay->getId(), mId, whitePointNits);
+ auto intError = mComposer.setLayerBrightness(mDisplay->getId(), mId, brightness);
return static_cast<Error>(intError);
}
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 0a605a8..334d6ec 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -37,6 +37,8 @@
#include "ComposerHal.h"
#include "Hal.h"
+#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
+#include <aidl/android/hardware/graphics/composer3/Capability.h>
#include <aidl/android/hardware/graphics/composer3/Color.h>
#include <aidl/android/hardware/graphics/composer3/Composition.h>
#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
@@ -161,6 +163,9 @@
[[clang::warn_unused_result]] virtual hal::Error setContentType(hal::ContentType) = 0;
[[clang::warn_unused_result]] virtual hal::Error getClientTargetProperty(
hal::ClientTargetProperty* outClientTargetProperty, float* outWhitePointNits) = 0;
+ [[clang::warn_unused_result]] virtual hal::Error getDisplayDecorationSupport(
+ std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
+ support) = 0;
};
namespace impl {
@@ -169,8 +174,9 @@
class Display : public HWC2::Display {
public:
- Display(android::Hwc2::Composer&, const std::unordered_set<hal::Capability>&, hal::HWDisplayId,
- hal::DisplayType);
+ Display(android::Hwc2::Composer&,
+ const std::unordered_set<aidl::android::hardware::graphics::composer3::Capability>&,
+ hal::HWDisplayId, hal::DisplayType);
~Display() override;
// Required by HWC2
@@ -233,6 +239,9 @@
hal::Error setContentType(hal::ContentType) override;
hal::Error getClientTargetProperty(hal::ClientTargetProperty* outClientTargetProperty,
float* outWhitePointNits) override;
+ hal::Error getDisplayDecorationSupport(
+ std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
+ support) override;
// Other Display methods
hal::HWDisplayId getId() const override { return mId; }
@@ -257,7 +266,8 @@
// this HWC2::Display, so these references are guaranteed to be valid for
// the lifetime of this object.
android::Hwc2::Composer& mComposer;
- const std::unordered_set<hal::Capability>& mCapabilities;
+ const std::unordered_set<aidl::android::hardware::graphics::composer3::Capability>&
+ mCapabilities;
const hal::HWDisplayId mId;
hal::DisplayType mType;
@@ -317,7 +327,7 @@
const std::string& name, bool mandatory, const std::vector<uint8_t>& value) = 0;
// AIDL HAL
- [[clang::warn_unused_result]] virtual hal::Error setWhitePointNits(float whitePointNits) = 0;
+ [[clang::warn_unused_result]] virtual hal::Error setBrightness(float brightness) = 0;
[[clang::warn_unused_result]] virtual hal::Error setBlockingRegion(
const android::Region& region) = 0;
};
@@ -329,8 +339,9 @@
class Layer : public HWC2::Layer {
public:
Layer(android::Hwc2::Composer& composer,
- const std::unordered_set<hal::Capability>& capabilities, HWC2::Display& display,
- hal::HWLayerId layerId);
+ const std::unordered_set<aidl::android::hardware::graphics::composer3::Capability>&
+ capabilities,
+ HWC2::Display& display, hal::HWLayerId layerId);
~Layer() override;
void onOwningDisplayDestroyed();
@@ -365,7 +376,7 @@
const std::vector<uint8_t>& value) override;
// AIDL HAL
- hal::Error setWhitePointNits(float whitePointNits) override;
+ hal::Error setBrightness(float brightness) override;
hal::Error setBlockingRegion(const android::Region& region) override;
private:
@@ -373,7 +384,8 @@
// this HWC2::Layer, so these references are guaranteed to be valid for
// the lifetime of this object.
android::Hwc2::Composer& mComposer;
- const std::unordered_set<hal::Capability>& mCapabilities;
+ const std::unordered_set<aidl::android::hardware::graphics::composer3::Capability>&
+ mCapabilities;
HWC2::Display* mDisplay;
hal::HWLayerId mId;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 2696bd8..6a3162e 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -71,6 +71,8 @@
#define RETURN_IF_HWC_ERROR(error, displayId, ...) \
RETURN_IF_HWC_ERROR_FOR(__FUNCTION__, error, displayId, __VA_ARGS__)
+using aidl::android::hardware::graphics::composer3::Capability;
+using aidl::android::hardware::graphics::composer3::DisplayCapability;
namespace hal = android::hardware::graphics::composer::hal;
namespace android {
@@ -118,13 +120,11 @@
return true;
}
-bool HWComposer::hasCapability(hal::Capability capability) const {
+bool HWComposer::hasCapability(Capability capability) const {
return mCapabilities.count(capability) > 0;
}
-bool HWComposer::hasDisplayCapability(
- HalDisplayId displayId,
- aidl::android::hardware::graphics::composer3::DisplayCapability capability) const {
+bool HWComposer::hasDisplayCapability(HalDisplayId displayId, DisplayCapability capability) const {
RETURN_IF_INVALID_DISPLAY(displayId, false);
return mDisplayData.at(displayId).hwcDisplay->hasCapability(capability);
}
@@ -785,6 +785,22 @@
return displayModeId;
}
+status_t HWComposer::getDisplayDecorationSupport(
+ PhysicalDisplayId displayId,
+ std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
+ support) {
+ RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
+ const auto error = mDisplayData[displayId].hwcDisplay->getDisplayDecorationSupport(support);
+ if (error == hal::Error::UNSUPPORTED) {
+ RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION);
+ }
+ if (error == hal::Error::BAD_PARAMETER) {
+ RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE);
+ }
+ RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
+ return NO_ERROR;
+}
+
status_t HWComposer::setAutoLowLatencyMode(PhysicalDisplayId displayId, bool on) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
const auto error = mDisplayData[displayId].hwcDisplay->setAutoLowLatencyMode(on);
@@ -952,7 +968,7 @@
static_assert(sizeof(hal::Capability) == sizeof(int32_t), "Capability size has changed");
auto capabilities = mComposer->getCapabilities();
for (auto capability : capabilities) {
- mCapabilities.emplace(static_cast<hal::Capability>(capability));
+ mCapabilities.emplace(capability);
}
}
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 29335d5..916c4b7 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -43,6 +43,8 @@
#include "HWC2.h"
#include "Hal.h"
+#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
+#include <aidl/android/hardware/graphics/composer3/Capability.h>
#include <aidl/android/hardware/graphics/composer3/Composition.h>
#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
@@ -110,7 +112,7 @@
virtual bool getDisplayIdentificationData(hal::HWDisplayId, uint8_t* outPort,
DisplayIdentificationData* outData) const = 0;
- virtual bool hasCapability(hal::Capability) const = 0;
+ virtual bool hasCapability(aidl::android::hardware::graphics::composer3::Capability) const = 0;
virtual bool hasDisplayCapability(
HalDisplayId,
aidl::android::hardware::graphics::composer3::DisplayCapability) const = 0;
@@ -261,6 +263,10 @@
virtual status_t setBootDisplayMode(PhysicalDisplayId, hal::HWConfigId) = 0;
virtual status_t clearBootDisplayMode(PhysicalDisplayId) = 0;
virtual std::optional<hal::HWConfigId> getPreferredBootDisplayMode(PhysicalDisplayId) = 0;
+ virtual status_t getDisplayDecorationSupport(
+ PhysicalDisplayId,
+ std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
+ support) = 0;
};
namespace impl {
@@ -277,7 +283,7 @@
bool getDisplayIdentificationData(hal::HWDisplayId, uint8_t* outPort,
DisplayIdentificationData* outData) const override;
- bool hasCapability(hal::Capability) const override;
+ bool hasCapability(aidl::android::hardware::graphics::composer3::Capability) const override;
bool hasDisplayCapability(
HalDisplayId,
aidl::android::hardware::graphics::composer3::DisplayCapability) const override;
@@ -392,6 +398,10 @@
status_t setBootDisplayMode(PhysicalDisplayId, hal::HWConfigId) override;
status_t clearBootDisplayMode(PhysicalDisplayId) override;
std::optional<hal::HWConfigId> getPreferredBootDisplayMode(PhysicalDisplayId) override;
+ status_t getDisplayDecorationSupport(
+ PhysicalDisplayId,
+ std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
+ support) override;
// for debugging ----------------------------------------------------------
void dump(std::string& out) const override;
@@ -447,7 +457,7 @@
std::unordered_map<HalDisplayId, DisplayData> mDisplayData;
std::unique_ptr<android::Hwc2::Composer> mComposer;
- std::unordered_set<hal::Capability> mCapabilities;
+ std::unordered_set<aidl::android::hardware::graphics::composer3::Capability> mCapabilities;
std::unordered_map<std::string, bool> mSupportedLayerGenericMetadata;
bool mRegisteredCallback = false;
diff --git a/services/surfaceflinger/DisplayHardware/Hal.h b/services/surfaceflinger/DisplayHardware/Hal.h
index 40c9761..4737034 100644
--- a/services/surfaceflinger/DisplayHardware/Hal.h
+++ b/services/surfaceflinger/DisplayHardware/Hal.h
@@ -135,8 +135,8 @@
return "AutoLowLatencyMode";
case aidl::android::hardware::graphics::composer3::DisplayCapability::SUSPEND:
return "Suspend";
- case aidl::android::hardware::graphics::composer3::DisplayCapability::DISPLAY_DECORATION:
- return "DisplayDecoration";
+ case aidl::android::hardware::graphics::composer3::DisplayCapability::DISPLAY_IDLE_TIMER:
+ return "DisplayIdleTimer";
default:
return "Unknown";
}
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index 746ac64..95d7b58 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -36,6 +36,7 @@
#include <algorithm>
#include <cinttypes>
+using aidl::android::hardware::graphics::composer3::Capability;
using aidl::android::hardware::graphics::composer3::DisplayCapability;
namespace android {
@@ -168,6 +169,20 @@
return unwrapRet(ret, kDefaultError);
}
+template <typename To, typename From>
+To translate(From x) {
+ return static_cast<To>(x);
+}
+
+template <typename To, typename From>
+std::vector<To> translate(const hidl_vec<From>& in) {
+ std::vector<To> out;
+ out.reserve(in.size());
+ std::transform(in.begin(), in.end(), std::back_inserter(out),
+ [](From x) { return translate<To>(x); });
+ return out;
+}
+
} // anonymous namespace
HidlComposer::HidlComposer(const std::string& serviceName) : mWriter(kWriterInitialSize) {
@@ -225,10 +240,11 @@
}
}
-std::vector<IComposer::Capability> HidlComposer::getCapabilities() {
- std::vector<IComposer::Capability> capabilities;
- mComposer->getCapabilities(
- [&](const auto& tmpCapabilities) { capabilities = tmpCapabilities; });
+std::vector<Capability> HidlComposer::getCapabilities() {
+ std::vector<Capability> capabilities;
+ mComposer->getCapabilities([&](const auto& tmpCapabilities) {
+ capabilities = translate<Capability>(tmpCapabilities);
+ });
return capabilities;
}
@@ -1101,15 +1117,6 @@
// Composer HAL 2.4
-namespace {
-template <typename T>
-void copyCapabilities(const T& tmpCaps, std::vector<DisplayCapability>* outCapabilities) {
- outCapabilities->resize(tmpCaps.size());
- std::transform(tmpCaps.begin(), tmpCaps.end(), outCapabilities->begin(),
- [](auto cap) { return static_cast<DisplayCapability>(cap); });
-}
-} // anonymous namespace
-
Error HidlComposer::getDisplayCapabilities(Display display,
std::vector<DisplayCapability>* outCapabilities) {
if (!mClient_2_3) {
@@ -1124,7 +1131,8 @@
if (error != V2_4::Error::NONE) {
return;
}
- copyCapabilities(tmpCaps, outCapabilities);
+ *outCapabilities =
+ translate<DisplayCapability>(tmpCaps);
});
} else {
mClient_2_3
@@ -1134,7 +1142,7 @@
return;
}
- copyCapabilities(tmpCaps, outCapabilities);
+ *outCapabilities = translate<DisplayCapability>(tmpCaps);
});
}
@@ -1295,7 +1303,7 @@
return Error::NONE;
}
-Error HidlComposer::setLayerWhitePointNits(Display, Layer, float) {
+Error HidlComposer::setLayerBrightness(Display, Layer, float) {
return Error::NONE;
}
@@ -1304,6 +1312,14 @@
return Error::NONE;
}
+Error HidlComposer::getDisplayDecorationSupport(
+ Display,
+ std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
+ support) {
+ support->reset();
+ return Error::UNSUPPORTED;
+}
+
void HidlComposer::registerCallback(ComposerCallback& callback) {
const bool vsyncSwitchingSupported =
isSupported(Hwc2::Composer::OptionalFeature::RefreshRateSwitching);
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
index 1ffca6e..71ae8b4 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
@@ -169,7 +169,8 @@
bool isSupported(OptionalFeature) const;
- std::vector<IComposer::Capability> getCapabilities() override;
+ std::vector<aidl::android::hardware::graphics::composer3::Capability> getCapabilities()
+ override;
std::string dumpDebugInfo() override;
void registerCallback(HWC2::ComposerCallback& callback) override;
@@ -320,12 +321,16 @@
float* outWhitePointNits) override;
// AIDL Composer HAL
- Error setLayerWhitePointNits(Display display, Layer layer, float whitePointNits) override;
+ Error setLayerBrightness(Display display, Layer layer, float brightness) override;
Error setLayerBlockingRegion(Display display, Layer layer,
const std::vector<IComposerClient::Rect>& blocking) override;
Error setBootDisplayConfig(Display displayId, Config) override;
Error clearBootDisplayConfig(Display displayId) override;
Error getPreferredBootDisplayConfig(Display displayId, Config*) override;
+ Error getDisplayDecorationSupport(
+ Display display,
+ std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
+ support) override;
private:
class CommandWriter : public CommandWriterBase {
diff --git a/services/surfaceflinger/FlagManager.cpp b/services/surfaceflinger/FlagManager.cpp
index 7602e6d..e09a192 100644
--- a/services/surfaceflinger/FlagManager.cpp
+++ b/services/surfaceflinger/FlagManager.cpp
@@ -19,8 +19,10 @@
#include <SurfaceFlingerProperties.sysprop.h>
#include <android-base/parsebool.h>
#include <android-base/parseint.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <log/log.h>
+#include <renderengine/RenderEngine.h>
#include <server_configurable_flags/get_flags.h>
#include <cinttypes>
@@ -34,6 +36,7 @@
base::StringAppendF(&result, "FlagManager values: \n");
base::StringAppendF(&result, "demo_flag: %" PRId64 "\n", demo_flag());
base::StringAppendF(&result, "use_adpf_cpu_hint: %s\n", use_adpf_cpu_hint() ? "true" : "false");
+ base::StringAppendF(&result, "use_skia_tracing: %s\n", use_skia_tracing() ? "true" : "false");
}
namespace {
@@ -97,4 +100,11 @@
return getValue("AdpfFeature__adpf_cpu_hint", sysPropVal, false);
}
+bool FlagManager::use_skia_tracing() const {
+ ALOGD("use_skia_tracing ?");
+ std::optional<bool> sysPropVal =
+ doParse<bool>(base::GetProperty(PROPERTY_SKIA_ATRACE_ENABLED, "").c_str());
+ return getValue("SkiaTracingFeature__use_skia_tracing", sysPropVal, false);
+}
+
} // namespace android
diff --git a/services/surfaceflinger/FlagManager.h b/services/surfaceflinger/FlagManager.h
index 24d83a2..e834142 100644
--- a/services/surfaceflinger/FlagManager.h
+++ b/services/surfaceflinger/FlagManager.h
@@ -33,6 +33,8 @@
bool use_adpf_cpu_hint() const;
+ bool use_skia_tracing() const;
+
private:
friend class FlagManagerTest;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index a039250..8081096 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1993,29 +1993,31 @@
setTransactionFlags(eTransactionNeeded);
}
-LayerProto* Layer::writeToProto(LayersProto& layersProto, uint32_t traceFlags,
- const DisplayDevice* display) {
+LayerProto* Layer::writeToProto(LayersProto& layersProto, uint32_t traceFlags) {
LayerProto* layerProto = layersProto.add_layers();
- writeToProtoDrawingState(layerProto, traceFlags, display);
+ writeToProtoDrawingState(layerProto);
writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags);
if (traceFlags & LayerTracing::TRACE_COMPOSITION) {
// Only populate for the primary display.
+ UnnecessaryLock assumeLocked(mFlinger->mStateLock); // called from the main thread.
+ const auto display = mFlinger->getDefaultDisplayDeviceLocked();
if (display) {
const auto compositionType = getCompositionType(*display);
layerProto->set_hwc_composition_type(static_cast<HwcCompositionType>(compositionType));
+ LayerProtoHelper::writeToProto(getVisibleRegion(display.get()),
+ [&]() { return layerProto->mutable_visible_region(); });
}
}
for (const sp<Layer>& layer : mDrawingChildren) {
- layer->writeToProto(layersProto, traceFlags, display);
+ layer->writeToProto(layersProto, traceFlags);
}
return layerProto;
}
-void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags,
- const DisplayDevice* display) {
+void Layer::writeToProtoDrawingState(LayerProto* layerInfo) {
const ui::Transform transform = getTransform();
auto buffer = getExternalTexture();
if (buffer != nullptr) {
@@ -2039,10 +2041,6 @@
LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(),
[&]() { return layerInfo->mutable_position(); });
LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); });
- if (traceFlags & LayerTracing::TRACE_COMPOSITION) {
- LayerProtoHelper::writeToProto(getVisibleRegion(display),
- [&]() { return layerInfo->mutable_visible_region(); });
- }
LayerProtoHelper::writeToProto(surfaceDamageRegion,
[&]() { return layerInfo->mutable_damage_region(); });
@@ -2161,8 +2159,7 @@
void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& screenToDisplay) {
Rect tmpBounds = getInputBounds();
if (!tmpBounds.isValid()) {
- info.flags = WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::NOT_FOCUSABLE;
- info.focusable = false;
+ info.setInputConfig(WindowInfo::InputConfig::NOT_FOCUSABLE, true);
info.touchableRegion.clear();
// A layer could have invalid input bounds and still expect to receive touch input if it has
// replaceTouchableRegionWithCrop. For that case, the input transform needs to be calculated
@@ -2309,7 +2306,6 @@
mDrawingState.inputInfo.ownerUid = mOwnerUid;
mDrawingState.inputInfo.ownerPid = mOwnerPid;
mDrawingState.inputInfo.inputFeatures = WindowInfo::Feature::NO_INPUT_CHANNEL;
- mDrawingState.inputInfo.flags = WindowInfo::Flag::NOT_TOUCH_MODAL;
mDrawingState.inputInfo.displayId = getLayerStack().id;
}
@@ -2327,7 +2323,9 @@
// We are just using these layers for occlusion detection in
// InputDispatcher, and obviously if they aren't visible they can't occlude
// anything.
- info.visible = hasInputInfo() ? canReceiveInput() : isVisible();
+ const bool visible = hasInputInfo() ? canReceiveInput() : isVisible();
+ info.setInputConfig(WindowInfo::InputConfig::NOT_VISIBLE, !visible);
+
info.alpha = getAlpha();
fillTouchOcclusionMode(info);
handleDropInputMode(info);
@@ -2349,8 +2347,9 @@
// Inherit the trusted state from the parent hierarchy, but don't clobber the trusted state
// if it was set by WM for a known system overlay
- info.trustedOverlay = info.trustedOverlay || isTrustedOverlay();
-
+ if (isTrustedOverlay()) {
+ info.inputConfig |= WindowInfo::InputConfig::TRUSTED_OVERLAY;
+ }
// If the layer is a clone, we need to crop the input region to cloned root to prevent
// touches from going outside the cloned area.
@@ -2482,7 +2481,7 @@
}
// Cloned layers shouldn't handle watch outside since their z order is not determined by
// WM or the client.
- mDrawingState.inputInfo.flags &= ~WindowInfo::Flag::WATCH_OUTSIDE_TOUCH;
+ mDrawingState.inputInfo.setInputConfig(WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH, false);
}
void Layer::updateClonedRelatives(const std::map<sp<Layer>, sp<Layer>>& clonedLayersMap) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index ddcd641..21dd5f4 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -686,12 +686,12 @@
bool isRemovedFromCurrentState() const;
- LayerProto* writeToProto(LayersProto& layersProto, uint32_t traceFlags, const DisplayDevice*);
+ LayerProto* writeToProto(LayersProto& layersProto, uint32_t traceFlags);
// Write states that are modified by the main thread. This includes drawing
// state as well as buffer data. This should be called in the main or tracing
// thread.
- void writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags, const DisplayDevice*);
+ void writeToProtoDrawingState(LayerProto* layerInfo);
// Write drawing or current state. If writing current state, the caller should hold the
// external mStateLock. If writing drawing state, this function should be called on the
// main or tracing thread.
@@ -897,6 +897,8 @@
virtual std::string getPendingBufferCounterName() { return ""; }
virtual bool updateGeometry() { return false; }
+ virtual bool simpleBufferUpdate(const layer_state_t&) const { return false; }
+
protected:
friend class impl::SurfaceInterceptor;
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index 015caa6..0506c47 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -156,14 +156,14 @@
void LayerProtoHelper::writeToProto(const renderengine::ExternalTexture& buffer,
std::function<ActiveBufferProto*()> getActiveBufferProto) {
- if (buffer.getBuffer()->getWidth() != 0 || buffer.getBuffer()->getHeight() != 0 ||
- buffer.getBuffer()->getUsage() != 0 || buffer.getBuffer()->getPixelFormat() != 0) {
+ if (buffer.getWidth() != 0 || buffer.getHeight() != 0 || buffer.getUsage() != 0 ||
+ buffer.getPixelFormat() != 0) {
// Use a lambda do avoid writing the object header when the object is empty
ActiveBufferProto* activeBufferProto = getActiveBufferProto();
- activeBufferProto->set_width(buffer.getBuffer()->getWidth());
- activeBufferProto->set_height(buffer.getBuffer()->getHeight());
- activeBufferProto->set_format(buffer.getBuffer()->getPixelFormat());
- activeBufferProto->set_usage(buffer.getBuffer()->getUsage());
+ activeBufferProto->set_width(buffer.getWidth());
+ activeBufferProto->set_height(buffer.getHeight());
+ activeBufferProto->set_stride(buffer.getUsage());
+ activeBufferProto->set_format(buffer.getPixelFormat());
}
}
@@ -175,12 +175,12 @@
}
InputWindowInfoProto* proto = getInputWindowInfoProto();
- proto->set_layout_params_flags(inputInfo.flags.get());
+ proto->set_layout_params_flags(inputInfo.layoutParamsFlags.get());
using U = std::underlying_type_t<WindowInfo::Type>;
// TODO(b/129481165): This static assert can be safely removed once conversion warnings
// are re-enabled.
static_assert(std::is_same_v<U, int32_t>);
- proto->set_layout_params_type(static_cast<U>(inputInfo.type));
+ proto->set_layout_params_type(static_cast<U>(inputInfo.layoutParamsType));
LayerProtoHelper::writeToProto({inputInfo.frameLeft, inputInfo.frameTop, inputInfo.frameRight,
inputInfo.frameBottom},
@@ -189,9 +189,10 @@
[&]() { return proto->mutable_touchable_region(); });
proto->set_surface_inset(inputInfo.surfaceInset);
- proto->set_visible(inputInfo.visible);
- proto->set_focusable(inputInfo.focusable);
- proto->set_has_wallpaper(inputInfo.hasWallpaper);
+ using InputConfig = gui::WindowInfo::InputConfig;
+ proto->set_visible(!inputInfo.inputConfig.test(InputConfig::NOT_VISIBLE));
+ proto->set_focusable(!inputInfo.inputConfig.test(InputConfig::NOT_FOCUSABLE));
+ proto->set_has_wallpaper(inputInfo.inputConfig.test(InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER));
proto->set_global_scale_factor(inputInfo.globalScaleFactor);
LayerProtoHelper::writeToProtoDeprecated(inputInfo.transform, proto->mutable_transform());
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
index 50b38c9..747032b 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
@@ -23,6 +23,7 @@
#include <mutex>
#include "EventThread.h"
+#include "VSyncTracker.h"
#include "VsyncController.h"
namespace android::scheduler {
@@ -114,7 +115,7 @@
std::chrono::nanoseconds mLastCallTime GUARDED_BY(mMutex) = 0ns;
};
-DispSyncSource::DispSyncSource(scheduler::VSyncDispatch& vSyncDispatch,
+DispSyncSource::DispSyncSource(VSyncDispatch& vSyncDispatch, VSyncTracker& vSyncTracker,
std::chrono::nanoseconds workDuration,
std::chrono::nanoseconds readyDuration, bool traceVsync,
const char* name)
@@ -122,6 +123,7 @@
mValue(base::StringPrintf("VSYNC-%s", name), 0),
mTraceVsync(traceVsync),
mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)),
+ mVSyncTracker(vSyncTracker),
mWorkDuration(base::StringPrintf("VsyncWorkDuration-%s", name), workDuration),
mReadyDuration(readyDuration) {
mCallbackRepeater =
@@ -180,10 +182,18 @@
}
if (callback != nullptr) {
- callback->onVSyncEvent(targetWakeupTime, vsyncTime, readyTime);
+ callback->onVSyncEvent(targetWakeupTime, {vsyncTime, readyTime});
}
}
+VSyncSource::VSyncData DispSyncSource::getLatestVSyncData() const {
+ std::lock_guard lock(mVsyncMutex);
+ nsecs_t expectedPresentTime = mVSyncTracker.nextAnticipatedVSyncTimeFrom(
+ systemTime() + mWorkDuration.get().count() + mReadyDuration.count());
+ nsecs_t deadline = expectedPresentTime - mWorkDuration.get().count() - mReadyDuration.count();
+ return {expectedPresentTime, deadline};
+}
+
void DispSyncSource::dump(std::string& result) const {
std::lock_guard lock(mVsyncMutex);
StringAppendF(&result, "DispSyncSource: %s(%s)\n", mName, mEnabled ? "enabled" : "disabled");
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h
index 2fce235..edcd3ac 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.h
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.h
@@ -24,11 +24,13 @@
namespace android::scheduler {
class CallbackRepeater;
+class VSyncTracker;
class DispSyncSource final : public VSyncSource {
public:
- DispSyncSource(VSyncDispatch& vSyncDispatch, std::chrono::nanoseconds workDuration,
- std::chrono::nanoseconds readyDuration, bool traceVsync, const char* name);
+ DispSyncSource(VSyncDispatch& vSyncDispatch, VSyncTracker& vSyncTracker,
+ std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration,
+ bool traceVsync, const char* name);
~DispSyncSource() override;
@@ -38,6 +40,7 @@
void setCallback(VSyncSource::Callback* callback) override;
void setDuration(std::chrono::nanoseconds workDuration,
std::chrono::nanoseconds readyDuration) override;
+ VSyncData getLatestVSyncData() const override;
void dump(std::string&) const override;
@@ -50,6 +53,8 @@
const bool mTraceVsync;
const std::string mVsyncOnLabel;
+ const VSyncTracker& mVSyncTracker;
+
std::unique_ptr<CallbackRepeater> mCallbackRepeater;
std::mutex mCallbackMutex;
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 627c49a..5ba8a1b 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -87,9 +87,10 @@
to_string(event.header.displayId).c_str(),
event.hotplug.connected ? "connected" : "disconnected");
case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
- return StringPrintf("VSync{displayId=%s, count=%u, expectedVSyncTimestamp=%" PRId64 "}",
+ return StringPrintf("VSync{displayId=%s, count=%u, expectedPresentationTime=%" PRId64
+ "}",
to_string(event.header.displayId).c_str(), event.vsync.count,
- event.vsync.expectedVSyncTimestamp);
+ event.vsync.vsyncData.preferredExpectedPresentationTime());
case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE:
return StringPrintf("ModeChanged{displayId=%s, modeId=%u}",
to_string(event.header.displayId).c_str(), event.modeChange.modeId);
@@ -107,14 +108,19 @@
}
DisplayEventReceiver::Event makeVSync(PhysicalDisplayId displayId, nsecs_t timestamp,
- uint32_t count, nsecs_t expectedVSyncTimestamp,
- nsecs_t deadlineTimestamp, int64_t vsyncId) {
+ uint32_t count, nsecs_t expectedPresentationTime,
+ nsecs_t deadlineTimestamp) {
DisplayEventReceiver::Event event;
event.header = {DisplayEventReceiver::DISPLAY_EVENT_VSYNC, displayId, timestamp};
event.vsync.count = count;
- event.vsync.expectedVSyncTimestamp = expectedVSyncTimestamp;
- event.vsync.deadlineTimestamp = deadlineTimestamp;
- event.vsync.vsyncId = vsyncId;
+ event.vsync.vsyncData.preferredFrameTimelineIndex = 0;
+ // Temporarily store the current vsync information in frameTimelines[0], marked as
+ // platform-preferred. When the event is dispatched later, the frame interval at that time is
+ // used with this information to generate multiple frame timeline choices.
+ event.vsync.vsyncData.frameTimelines[0] = {.vsyncId = FrameTimelineInfo::INVALID_VSYNC_ID,
+ .deadlineTimestamp = deadlineTimestamp,
+ .expectedPresentationTime =
+ expectedPresentationTime};
return event;
}
@@ -182,11 +188,18 @@
}
binder::Status EventThreadConnection::requestNextVsync() {
- ATRACE_NAME("requestNextVsync");
+ ATRACE_CALL();
mEventThread->requestNextVsync(this);
return binder::Status::ok();
}
+binder::Status EventThreadConnection::getLatestVsyncEventData(
+ ParcelableVsyncEventData* outVsyncEventData) {
+ ATRACE_CALL();
+ outVsyncEventData->vsync = mEventThread->getLatestVsyncEventData(this);
+ return binder::Status::ok();
+}
+
status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) {
constexpr auto toStatus = [](ssize_t size) {
return size < 0 ? status_t(size) : status_t(NO_ERROR);
@@ -331,6 +344,21 @@
}
}
+VsyncEventData EventThread::getLatestVsyncEventData(
+ const sp<EventThreadConnection>& connection) const {
+ VsyncEventData vsyncEventData;
+ nsecs_t frameInterval = mGetVsyncPeriodFunction(connection->mOwnerUid);
+ vsyncEventData.frameInterval = frameInterval;
+ VSyncSource::VSyncData vsyncData;
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ vsyncData = mVSyncSource->getLatestVSyncData();
+ }
+ generateFrameTimeline(vsyncEventData, frameInterval, systemTime(SYSTEM_TIME_MONOTONIC),
+ vsyncData.expectedPresentationTime, vsyncData.deadlineTimestamp);
+ return vsyncEventData;
+}
+
void EventThread::onScreenReleased() {
std::lock_guard<std::mutex> lock(mMutex);
if (!mVSyncState || mVSyncState->synthetic) {
@@ -351,14 +379,13 @@
mCondition.notify_all();
}
-void EventThread::onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp,
- nsecs_t deadlineTimestamp) {
+void EventThread::onVSyncEvent(nsecs_t timestamp, VSyncSource::VSyncData vsyncData) {
std::lock_guard<std::mutex> lock(mMutex);
LOG_FATAL_IF(!mVSyncState);
- const int64_t vsyncId = generateToken(timestamp, deadlineTimestamp, expectedVSyncTimestamp);
mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count,
- expectedVSyncTimestamp, deadlineTimestamp, vsyncId));
+ vsyncData.expectedPresentationTime,
+ vsyncData.deadlineTimestamp));
mCondition.notify_all();
}
@@ -493,16 +520,9 @@
const auto now = systemTime(SYSTEM_TIME_MONOTONIC);
const auto deadlineTimestamp = now + timeout.count();
const auto expectedVSyncTime = deadlineTimestamp + timeout.count();
- const int64_t vsyncId = [&] {
- if (mTokenManager != nullptr) {
- return mTokenManager->generateTokenForPredictions(
- {now, deadlineTimestamp, expectedVSyncTime});
- }
- return FrameTimelineInfo::INVALID_VSYNC_ID;
- }();
mPendingEvents.push_back(makeVSync(mVSyncState->displayId, now,
++mVSyncState->count, expectedVSyncTime,
- deadlineTimestamp, vsyncId));
+ deadlineTimestamp));
}
}
}
@@ -512,7 +532,8 @@
const sp<EventThreadConnection>& connection) const {
const auto throttleVsync = [&] {
return mThrottleVsyncCallback &&
- mThrottleVsyncCallback(event.vsync.expectedVSyncTimestamp, connection->mOwnerUid);
+ mThrottleVsyncCallback(event.vsync.vsyncData.preferredExpectedPresentationTime(),
+ connection->mOwnerUid);
};
switch (event.header.type) {
@@ -562,35 +583,34 @@
}
int64_t EventThread::generateToken(nsecs_t timestamp, nsecs_t deadlineTimestamp,
- nsecs_t expectedVSyncTimestamp) const {
+ nsecs_t expectedPresentationTime) const {
if (mTokenManager != nullptr) {
return mTokenManager->generateTokenForPredictions(
- {timestamp, deadlineTimestamp, expectedVSyncTimestamp});
+ {timestamp, deadlineTimestamp, expectedPresentationTime});
}
return FrameTimelineInfo::INVALID_VSYNC_ID;
}
-void EventThread::generateFrameTimeline(DisplayEventReceiver::Event& event) const {
+void EventThread::generateFrameTimeline(VsyncEventData& outVsyncEventData, nsecs_t frameInterval,
+ nsecs_t timestamp,
+ nsecs_t preferredExpectedPresentationTime,
+ nsecs_t preferredDeadlineTimestamp) const {
// Add 1 to ensure the preferredFrameTimelineIndex entry (when multiplier == 0) is included.
- for (int multiplier = -DisplayEventReceiver::kFrameTimelinesLength + 1, currentIndex = 0;
- currentIndex < DisplayEventReceiver::kFrameTimelinesLength; multiplier++) {
- nsecs_t deadline = event.vsync.deadlineTimestamp + multiplier * event.vsync.frameInterval;
+ for (int64_t multiplier = -VsyncEventData::kFrameTimelinesLength + 1, currentIndex = 0;
+ currentIndex < VsyncEventData::kFrameTimelinesLength; multiplier++) {
+ nsecs_t deadlineTimestamp = preferredDeadlineTimestamp + multiplier * frameInterval;
// Valid possible frame timelines must have future values.
- if (deadline > event.header.timestamp) {
+ if (deadlineTimestamp > timestamp) {
if (multiplier == 0) {
- event.vsync.preferredFrameTimelineIndex = currentIndex;
- event.vsync.frameTimelines[currentIndex] =
- {.vsyncId = event.vsync.vsyncId,
- .deadlineTimestamp = event.vsync.deadlineTimestamp,
- .expectedVSyncTimestamp = event.vsync.expectedVSyncTimestamp};
- } else {
- nsecs_t expectedVSync =
- event.vsync.expectedVSyncTimestamp + multiplier * event.vsync.frameInterval;
- event.vsync.frameTimelines[currentIndex] =
- {.vsyncId = generateToken(event.header.timestamp, deadline, expectedVSync),
- .deadlineTimestamp = deadline,
- .expectedVSyncTimestamp = expectedVSync};
+ outVsyncEventData.preferredFrameTimelineIndex = currentIndex;
}
+ nsecs_t expectedPresentationTime =
+ preferredExpectedPresentationTime + multiplier * frameInterval;
+ outVsyncEventData.frameTimelines[currentIndex] =
+ {.vsyncId =
+ generateToken(timestamp, deadlineTimestamp, expectedPresentationTime),
+ .deadlineTimestamp = deadlineTimestamp,
+ .expectedPresentationTime = expectedPresentationTime};
currentIndex++;
}
}
@@ -601,8 +621,11 @@
for (const auto& consumer : consumers) {
DisplayEventReceiver::Event copy = event;
if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
- copy.vsync.frameInterval = mGetVsyncPeriodFunction(consumer->mOwnerUid);
- generateFrameTimeline(copy);
+ const int64_t frameInterval = mGetVsyncPeriodFunction(consumer->mOwnerUid);
+ copy.vsync.vsyncData.frameInterval = frameInterval;
+ generateFrameTimeline(copy.vsync.vsyncData, frameInterval, copy.header.timestamp,
+ event.vsync.vsyncData.preferredExpectedPresentationTime(),
+ event.vsync.vsyncData.preferredDeadlineTimestamp());
}
switch (consumer->postEvent(copy)) {
case NO_ERROR:
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index fa9af09..c406478 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -45,6 +45,9 @@
class TokenManager;
} // namespace frametimeline
+using gui::ParcelableVsyncEventData;
+using gui::VsyncEventData;
+
// ---------------------------------------------------------------------------
using ResyncCallback = std::function<void()>;
@@ -62,11 +65,16 @@
class VSyncSource {
public:
+ class VSyncData {
+ public:
+ nsecs_t expectedPresentationTime;
+ nsecs_t deadlineTimestamp;
+ };
+
class Callback {
public:
virtual ~Callback() {}
- virtual void onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp,
- nsecs_t deadlineTimestamp) = 0;
+ virtual void onVSyncEvent(nsecs_t when, VSyncData vsyncData) = 0;
};
virtual ~VSyncSource() {}
@@ -76,6 +84,7 @@
virtual void setCallback(Callback* callback) = 0;
virtual void setDuration(std::chrono::nanoseconds workDuration,
std::chrono::nanoseconds readyDuration) = 0;
+ virtual VSyncData getLatestVSyncData() const = 0;
virtual void dump(std::string& result) const = 0;
};
@@ -91,6 +100,7 @@
binder::Status stealReceiveChannel(gui::BitTube* outChannel) override;
binder::Status setVsyncRate(int rate) override;
binder::Status requestNextVsync() override; // asynchronous
+ binder::Status getLatestVsyncEventData(ParcelableVsyncEventData* outVsyncEventData) override;
// Called in response to requestNextVsync.
const ResyncCallback resyncCallback;
@@ -140,6 +150,8 @@
virtual void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) = 0;
// Requests the next vsync. If resetIdleTimer is set to true, it resets the idle timer.
virtual void requestNextVsync(const sp<EventThreadConnection>& connection) = 0;
+ virtual VsyncEventData getLatestVsyncEventData(
+ const sp<EventThreadConnection>& connection) const = 0;
// Retrieves the number of event connections tracked by this EventThread.
virtual size_t getEventThreadConnectionCount() = 0;
@@ -164,6 +176,8 @@
status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override;
void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) override;
void requestNextVsync(const sp<EventThreadConnection>& connection) override;
+ VsyncEventData getLatestVsyncEventData(
+ const sp<EventThreadConnection>& connection) const override;
// called before the screen is turned off from main thread
void onScreenReleased() override;
@@ -201,12 +215,13 @@
REQUIRES(mMutex);
// Implements VSyncSource::Callback
- void onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp,
- nsecs_t deadlineTimestamp) override;
+ void onVSyncEvent(nsecs_t timestamp, VSyncSource::VSyncData vsyncData) override;
int64_t generateToken(nsecs_t timestamp, nsecs_t deadlineTimestamp,
- nsecs_t expectedVSyncTimestamp) const;
- void generateFrameTimeline(DisplayEventReceiver::Event& event) const;
+ nsecs_t expectedPresentationTime) const;
+ void generateFrameTimeline(VsyncEventData& outVsyncEventData, nsecs_t frameInterval,
+ nsecs_t timestamp, nsecs_t preferredExpectedPresentationTime,
+ nsecs_t preferredDeadlineTimestamp) const;
const std::unique_ptr<VSyncSource> mVSyncSource GUARDED_BY(mMutex);
frametimeline::TokenManager* const mTokenManager;
diff --git a/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.cpp b/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.cpp
index d9d64ae..c233455 100644
--- a/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.cpp
+++ b/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.cpp
@@ -51,7 +51,8 @@
return std::nullopt;
}
-std::vector<FrameRateOverride> FrameRateOverrideMappings::getAllFrameRateOverrides() {
+std::vector<FrameRateOverride> FrameRateOverrideMappings::getAllFrameRateOverrides(
+ bool supportsFrameRateOverrideByContent) {
std::lock_guard lock(mFrameRateOverridesLock);
std::vector<FrameRateOverride> overrides;
overrides.reserve(std::max({mFrameRateOverridesFromGameManager.size(),
@@ -67,6 +68,11 @@
overrides.emplace_back(FrameRateOverride{uid, frameRate.getValue()});
}
}
+
+ if (!supportsFrameRateOverrideByContent) {
+ return overrides;
+ }
+
for (const auto& [uid, frameRate] : mFrameRateOverridesByContent) {
if (std::find_if(overrides.begin(), overrides.end(),
[uid = uid](auto i) { return i.uid == uid; }) == overrides.end()) {
diff --git a/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.h b/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.h
index 278f87c..4185a4c 100644
--- a/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.h
+++ b/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.h
@@ -32,7 +32,8 @@
std::optional<Fps> getFrameRateOverrideForUid(uid_t uid,
bool supportsFrameRateOverrideByContent) const
EXCLUDES(mFrameRateOverridesLock);
- std::vector<FrameRateOverride> getAllFrameRateOverrides() EXCLUDES(mFrameRateOverridesLock);
+ std::vector<FrameRateOverride> getAllFrameRateOverrides(bool supportsFrameRateOverrideByContent)
+ EXCLUDES(mFrameRateOverridesLock);
void dump(std::string& result) const;
bool updateFrameRateOverridesByContent(const UidToFrameRateOverride& frameRateOverrides)
EXCLUDES(mFrameRateOverridesLock);
diff --git a/services/surfaceflinger/Scheduler/InjectVSyncSource.h b/services/surfaceflinger/Scheduler/InjectVSyncSource.h
index 016b076..760a4ee 100644
--- a/services/surfaceflinger/Scheduler/InjectVSyncSource.h
+++ b/services/surfaceflinger/Scheduler/InjectVSyncSource.h
@@ -39,13 +39,14 @@
nsecs_t deadlineTimestamp) {
std::lock_guard<std::mutex> lock(mCallbackMutex);
if (mCallback) {
- mCallback->onVSyncEvent(when, expectedVSyncTimestamp, deadlineTimestamp);
+ mCallback->onVSyncEvent(when, {expectedVSyncTimestamp, deadlineTimestamp});
}
}
const char* getName() const override { return "inject"; }
void setVSyncEnabled(bool) override {}
void setDuration(std::chrono::nanoseconds, std::chrono::nanoseconds) override {}
+ VSyncData getLatestVSyncData() const override { return {}; }
void dump(std::string&) const override {}
private:
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 0efc28b..5f64efa 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -83,8 +83,7 @@
void LayerHistory::registerLayer(Layer* layer, LayerVoteType type) {
std::lock_guard lock(mLock);
- LOG_ALWAYS_FATAL_IF(findLayer(layer->getSequence()).first !=
- LayerHistory::layerStatus::NotFound,
+ LOG_ALWAYS_FATAL_IF(findLayer(layer->getSequence()).first != LayerStatus::NotFound,
"%s already registered", layer->getName().c_str());
auto info = std::make_unique<LayerInfo>(layer->getName(), layer->getOwnerUid(), type);
@@ -108,9 +107,9 @@
auto id = layer->getSequence();
auto [found, layerPair] = findLayer(id);
- if (found == LayerHistory::layerStatus::NotFound) {
+ if (found == LayerStatus::NotFound) {
// Offscreen layer
- ALOGV("LayerHistory::record: %s not registered", layer->getName().c_str());
+ ALOGV("%s: %s not registered", __func__, layer->getName().c_str());
return;
}
@@ -126,16 +125,15 @@
info->setLastPresentTime(presentTime, now, updateType, mModeChangePending, layerProps);
// Activate layer if inactive.
- if (found == LayerHistory::layerStatus::LayerInInactiveMap) {
+ if (found == LayerStatus::LayerInInactiveMap) {
mActiveLayerInfos.insert(
{id, std::make_pair(layerPair->first, std::move(layerPair->second))});
mInactiveLayerInfos.erase(id);
}
}
-LayerHistory::Summary LayerHistory::summarize(const RefreshRateConfigs& refreshRateConfigs,
- nsecs_t now) {
- LayerHistory::Summary summary;
+auto LayerHistory::summarize(const RefreshRateConfigs& configs, nsecs_t now) -> Summary {
+ Summary summary;
std::lock_guard lock(mLock);
@@ -148,9 +146,9 @@
ALOGV("%s has priority: %d %s focused", info->getName().c_str(), frameRateSelectionPriority,
layerFocused ? "" : "not");
- const auto vote = info->getRefreshRateVote(refreshRateConfigs, now);
+ const auto vote = info->getRefreshRateVote(configs, now);
// Skip NoVote layer as those don't have any requirements
- if (vote.type == LayerHistory::LayerVoteType::NoVote) {
+ if (vote.type == LayerVoteType::NoVote) {
continue;
}
@@ -187,7 +185,7 @@
it = mInactiveLayerInfos.erase(it);
} else {
if (CC_UNLIKELY(mTraceEnabled)) {
- trace(*info, LayerHistory::LayerVoteType::NoVote, 0);
+ trace(*info, LayerVoteType::NoVote, 0);
}
info->onLayerInactive(now);
it++;
@@ -224,7 +222,7 @@
it++;
} else {
if (CC_UNLIKELY(mTraceEnabled)) {
- trace(*info, LayerHistory::LayerVoteType::NoVote, 0);
+ trace(*info, LayerVoteType::NoVote, 0);
}
info->onLayerInactive(now);
// move this to the inactive map
@@ -251,37 +249,23 @@
float LayerHistory::getLayerFramerate(nsecs_t now, int32_t id) const {
std::lock_guard lock(mLock);
auto [found, layerPair] = findLayer(id);
- if (found != LayerHistory::layerStatus::NotFound) {
+ if (found != LayerStatus::NotFound) {
return layerPair->second->getFps(now).getValue();
}
return 0.f;
}
-std::pair<LayerHistory::layerStatus, LayerHistory::LayerPair*> LayerHistory::findLayer(int32_t id) {
+auto LayerHistory::findLayer(int32_t id) -> std::pair<LayerStatus, LayerPair*> {
// the layer could be in either the active or inactive map, try both
auto it = mActiveLayerInfos.find(id);
if (it != mActiveLayerInfos.end()) {
- return std::make_pair(LayerHistory::layerStatus::LayerInActiveMap, &(it->second));
+ return {LayerStatus::LayerInActiveMap, &(it->second)};
}
it = mInactiveLayerInfos.find(id);
if (it != mInactiveLayerInfos.end()) {
- return std::make_pair(LayerHistory::layerStatus::LayerInInactiveMap, &(it->second));
+ return {LayerStatus::LayerInInactiveMap, &(it->second)};
}
- return std::make_pair(LayerHistory::layerStatus::NotFound, nullptr);
-}
-
-std::pair<LayerHistory::layerStatus, const LayerHistory::LayerPair*> LayerHistory::findLayer(
- int32_t id) const {
- // the layer could be in either the active or inactive map, try both
- auto it = mActiveLayerInfos.find(id);
- if (it != mActiveLayerInfos.end()) {
- return std::make_pair(LayerHistory::layerStatus::LayerInActiveMap, &(it->second));
- }
- it = mInactiveLayerInfos.find(id);
- if (it != mInactiveLayerInfos.end()) {
- return std::make_pair(LayerHistory::layerStatus::LayerInInactiveMap, &(it->second));
- }
- return std::make_pair(LayerHistory::layerStatus::NotFound, nullptr);
+ return {LayerStatus::NotFound, nullptr};
}
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index cc55700..7b6096f 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -89,7 +89,7 @@
// worst case time complexity is O(2 * inactive + active)
void partitionLayers(nsecs_t now) REQUIRES(mLock);
- enum class layerStatus {
+ enum class LayerStatus {
NotFound,
LayerInActiveMap,
LayerInInactiveMap,
@@ -97,9 +97,11 @@
// looks up a layer by sequence id in both layerInfo maps.
// The first element indicates if and where the item was found
- std::pair<layerStatus, LayerHistory::LayerPair*> findLayer(int32_t id) REQUIRES(mLock);
- std::pair<layerStatus, const LayerHistory::LayerPair*> findLayer(int32_t id) const
- REQUIRES(mLock);
+ std::pair<LayerStatus, LayerPair*> findLayer(int32_t id) REQUIRES(mLock);
+
+ std::pair<LayerStatus, const LayerPair*> findLayer(int32_t id) const REQUIRES(mLock) {
+ return const_cast<LayerHistory*>(this)->findLayer(id);
+ }
mutable std::mutex mLock;
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index a020e2c..712cd5b 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -191,7 +191,8 @@
for (int i = 0; i < n; i++) {
if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
auto& vsync = buffer[i].vsync;
- mHandler->dispatchFrame(vsync.vsyncId, vsync.expectedVSyncTimestamp);
+ mHandler->dispatchFrame(vsync.vsyncData.preferredVsyncId(),
+ vsync.vsyncData.preferredExpectedPresentationTime());
break;
}
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 665d36982..82ff2fa 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -134,7 +134,8 @@
std::unique_ptr<VSyncSource> Scheduler::makePrimaryDispSyncSource(
const char* name, std::chrono::nanoseconds workDuration,
std::chrono::nanoseconds readyDuration, bool traceVsync) {
- return std::make_unique<scheduler::DispSyncSource>(getVsyncDispatch(), workDuration,
+ return std::make_unique<scheduler::DispSyncSource>(mVsyncSchedule->getDispatch(),
+ mVsyncSchedule->getTracker(), workDuration,
readyDuration, traceVsync, name);
}
@@ -262,8 +263,12 @@
}
void Scheduler::onFrameRateOverridesChanged(ConnectionHandle handle, PhysicalDisplayId displayId) {
+ const auto refreshRateConfigs = holdRefreshRateConfigs();
+ const bool supportsFrameRateOverrideByContent =
+ refreshRateConfigs->supportsFrameRateOverrideByContent();
+
std::vector<FrameRateOverride> overrides =
- mFrameRateOverrideMappings.getAllFrameRateOverrides();
+ mFrameRateOverrideMappings.getAllFrameRateOverrides(supportsFrameRateOverrideByContent);
android::EventThread* thread;
{
@@ -530,50 +535,13 @@
}
void Scheduler::chooseRefreshRateForContent() {
- {
- std::scoped_lock lock(mRefreshRateConfigsLock);
- if (!mRefreshRateConfigs->canSwitch()) return;
- }
+ const auto configs = holdRefreshRateConfigs();
+ if (!configs->canSwitch()) return;
ATRACE_CALL();
- DisplayModePtr newMode;
- GlobalSignals consideredSignals;
-
- bool frameRateChanged;
- bool frameRateOverridesChanged;
-
- const auto refreshRateConfigs = holdRefreshRateConfigs();
- LayerHistory::Summary summary = mLayerHistory.summarize(*refreshRateConfigs, systemTime());
- {
- std::lock_guard<std::mutex> lock(mPolicyLock);
- mPolicy.contentRequirements = std::move(summary);
-
- std::tie(newMode, consideredSignals) = chooseDisplayMode();
- frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps());
-
- if (mPolicy.mode == newMode) {
- // We don't need to change the display mode, but we might need to send an event
- // about a mode change, since it was suppressed due to a previous idleConsidered
- if (!consideredSignals.idle) {
- dispatchCachedReportedMode();
- }
- frameRateChanged = false;
- } else {
- mPolicy.mode = newMode;
- frameRateChanged = true;
- }
- }
- if (frameRateChanged) {
- const auto newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newMode->getId());
-
- mSchedulerCallback.changeRefreshRate(newRefreshRate,
- consideredSignals.idle ? DisplayModeEvent::None
- : DisplayModeEvent::Changed);
- }
- if (frameRateOverridesChanged) {
- mSchedulerCallback.triggerOnFrameRateOverridesChanged();
- }
+ LayerHistory::Summary summary = mLayerHistory.summarize(*configs, systemTime());
+ applyPolicy(&Policy::contentRequirements, std::move(summary));
}
void Scheduler::resetIdleTimer() {
@@ -635,7 +603,7 @@
}
void Scheduler::idleTimerCallback(TimerState state) {
- handleTimerStateChanged(&mPolicy.idleTimer, state);
+ applyPolicy(&Policy::idleTimer, state);
ATRACE_INT("ExpiredIdleTimer", static_cast<int>(state));
}
@@ -645,14 +613,14 @@
// Clear layer history to get fresh FPS detection.
// NOTE: Instead of checking all the layers, we should be checking the layer
// that is currently on top. b/142507166 will give us this capability.
- if (handleTimerStateChanged(&mPolicy.touch, touch)) {
+ if (applyPolicy(&Policy::touch, touch).touch) {
mLayerHistory.clear();
}
ATRACE_INT("TouchState", static_cast<int>(touch));
}
void Scheduler::displayPowerTimerCallback(TimerState state) {
- handleTimerStateChanged(&mPolicy.displayPowerTimer, state);
+ applyPolicy(&Policy::displayPowerTimer, state);
ATRACE_INT("ExpiredDisplayPowerTimer", static_cast<int>(state));
}
@@ -681,10 +649,10 @@
bool Scheduler::updateFrameRateOverrides(GlobalSignals consideredSignals, Fps displayRefreshRate) {
const auto refreshRateConfigs = holdRefreshRateConfigs();
- if (!refreshRateConfigs->supportsFrameRateOverrideByContent()) {
- return false;
- }
+ // we always update mFrameRateOverridesByContent here
+ // supportsFrameRateOverridesByContent will be checked
+ // when getting FrameRateOverrides from mFrameRateOverrideMappings
if (!consideredSignals.idle) {
const auto frameRateOverrides =
refreshRateConfigs->getFrameRateOverrides(mPolicy.contentRequirements,
@@ -694,8 +662,8 @@
return false;
}
-template <class T>
-bool Scheduler::handleTimerStateChanged(T* currentState, T newState) {
+template <typename S, typename T>
+auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals {
DisplayModePtr newMode;
GlobalSignals consideredSignals;
@@ -705,15 +673,17 @@
const auto refreshRateConfigs = holdRefreshRateConfigs();
{
std::lock_guard<std::mutex> lock(mPolicyLock);
- if (*currentState == newState) {
- return false;
- }
- *currentState = newState;
+
+ auto& currentState = mPolicy.*statePtr;
+ if (currentState == newState) return {};
+ currentState = std::forward<T>(newState);
+
std::tie(newMode, consideredSignals) = chooseDisplayMode();
frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps());
+
if (mPolicy.mode == newMode) {
// We don't need to change the display mode, but we might need to send an event
- // about a mode change, since it was suppressed due to a previous idleConsidered
+ // about a mode change, since it was suppressed if previously considered idle.
if (!consideredSignals.idle) {
dispatchCachedReportedMode();
}
@@ -732,7 +702,7 @@
if (frameRateOverridesChanged) {
mSchedulerCallback.triggerOnFrameRateOverridesChanged();
}
- return consideredSignals.touch;
+ return consideredSignals;
}
auto Scheduler::chooseDisplayMode() -> std::pair<DisplayModePtr, GlobalSignals> {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 468c4cc..9c32b1f 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -263,14 +263,17 @@
void touchTimerCallback(TimerState);
void displayPowerTimerCallback(TimerState);
- // handles various timer features to change the refresh rate.
- template <class T>
- bool handleTimerStateChanged(T* currentState, T newState);
-
void setVsyncPeriod(nsecs_t period);
using GlobalSignals = RefreshRateConfigs::GlobalSignals;
+ struct Policy;
+
+ // Sets the S state of the policy to the T value under mPolicyLock, and chooses a display mode
+ // that fulfills the new policy if the state changed. Returns the signals that were considered.
+ template <typename S, typename T>
+ GlobalSignals applyPolicy(S Policy::*, T&&) EXCLUDES(mPolicyLock);
+
// Returns the display mode that fulfills the policy, and the signals that were considered.
std::pair<DisplayModePtr, GlobalSignals> chooseDisplayMode() REQUIRES(mPolicyLock);
@@ -323,7 +326,7 @@
mutable std::mutex mPolicyLock;
- struct {
+ struct Policy {
// Policy for choosing the display mode.
LayerHistory::Summary contentRequirements;
TimerState idleTimer = TimerState::Reset;
diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.cpp b/services/surfaceflinger/Scheduler/VsyncModulator.cpp
index 245db0f..be57b2a 100644
--- a/services/surfaceflinger/Scheduler/VsyncModulator.cpp
+++ b/services/surfaceflinger/Scheduler/VsyncModulator.cpp
@@ -134,16 +134,27 @@
return mVsyncConfig;
}
-const VsyncModulator::VsyncConfig& VsyncModulator::getNextVsyncConfig() const {
+auto VsyncModulator::getNextVsyncConfigType() const -> VsyncConfigType {
// Early offsets are used if we're in the middle of a refresh rate
// change, or if we recently begin a transaction.
if (!mEarlyWakeupRequests.empty() || mTransactionSchedule == Schedule::EarlyEnd ||
mEarlyTransactionFrames > 0 || mRefreshRateChangePending) {
- return mVsyncConfigSet.early;
+ return VsyncConfigType::Early;
} else if (mEarlyGpuFrames > 0) {
- return mVsyncConfigSet.earlyGpu;
+ return VsyncConfigType::EarlyGpu;
} else {
- return mVsyncConfigSet.late;
+ return VsyncConfigType::Late;
+ }
+}
+
+const VsyncModulator::VsyncConfig& VsyncModulator::getNextVsyncConfig() const {
+ switch (getNextVsyncConfigType()) {
+ case VsyncConfigType::Early:
+ return mVsyncConfigSet.early;
+ case VsyncConfigType::EarlyGpu:
+ return mVsyncConfigSet.earlyGpu;
+ case VsyncConfigType::Late:
+ return mVsyncConfigSet.late;
}
}
@@ -176,4 +187,9 @@
static_cast<void>(updateVsyncConfigLocked());
}
+bool VsyncModulator::isVsyncConfigDefault() const {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return getNextVsyncConfigType() == VsyncConfigType::Late;
+}
+
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.h b/services/surfaceflinger/Scheduler/VsyncModulator.h
index 2000c54..537cae1 100644
--- a/services/surfaceflinger/Scheduler/VsyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VsyncModulator.h
@@ -109,11 +109,16 @@
[[nodiscard]] VsyncConfigOpt onDisplayRefresh(bool usedGpuComposition);
+ [[nodiscard]] bool isVsyncConfigDefault() const;
+
protected:
// Called from unit tests as well
void binderDied(const wp<IBinder>&) override EXCLUDES(mMutex);
private:
+ enum class VsyncConfigType { Early, EarlyGpu, Late };
+
+ VsyncConfigType getNextVsyncConfigType() const REQUIRES(mMutex);
const VsyncConfig& getNextVsyncConfig() const REQUIRES(mMutex);
[[nodiscard]] VsyncConfig updateVsyncConfig() EXCLUDES(mMutex);
[[nodiscard]] VsyncConfig updateVsyncConfigLocked() REQUIRES(mMutex);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 4a5413b..9716d8e 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -141,6 +141,7 @@
#include "android-base/stringprintf.h"
#include "android-base/strings.h"
+#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
#define MAIN_THREAD ACQUIRE(mStateLock) RELEASE(mStateLock)
@@ -163,6 +164,8 @@
#define NO_THREAD_SAFETY_ANALYSIS \
_Pragma("GCC error \"Prefer MAIN_THREAD macros or {Conditional,Timed,Unnecessary}Lock.\"")
+using aidl::android::hardware::graphics::common::DisplayDecorationSupport;
+using aidl::android::hardware::graphics::composer3::Capability;
using aidl::android::hardware::graphics::composer3::DisplayCapability;
namespace android {
@@ -247,11 +250,6 @@
const status_t status;
};
-struct SCOPED_CAPABILITY UnnecessaryLock {
- explicit UnnecessaryLock(Mutex& mutex) ACQUIRE(mutex) {}
- ~UnnecessaryLock() RELEASE() {}
-};
-
// TODO(b/141333600): Consolidate with DisplayMode::Builder::getDefaultDensity.
constexpr float FALLBACK_DENSITY = ACONFIGURATION_DENSITY_TV;
@@ -497,8 +495,6 @@
mRefreshRateOverlaySpinner = property_get_bool("sf.debug.show_refresh_rate_overlay_spinner", 0);
- enableLatchUnsignaledConfig = getLatchUnsignaledConfig();
-
if (!mIsUserBuild && base::GetBoolProperty("debug.sf.enable_transaction_tracing"s, true)) {
mTransactionTracing.emplace();
}
@@ -507,11 +503,13 @@
LatchUnsignaledConfig SurfaceFlinger::getLatchUnsignaledConfig() {
if (base::GetBoolProperty("debug.sf.latch_unsignaled"s, false)) {
return LatchUnsignaledConfig::Always;
- } else if (base::GetBoolProperty("debug.sf.auto_latch_unsignaled"s, false)) {
- return LatchUnsignaledConfig::Auto;
- } else {
- return LatchUnsignaledConfig::Disabled;
}
+
+ if (base::GetBoolProperty("debug.sf.auto_latch_unsignaled"s, true)) {
+ return LatchUnsignaledConfig::AutoSingleLayer;
+ }
+
+ return LatchUnsignaledConfig::Disabled;
}
SurfaceFlinger::~SurfaceFlinger() = default;
@@ -712,6 +710,7 @@
mFlagManager = std::make_unique<android::FlagManager>();
mFrameTracer->initialize();
mFrameTimeline->onBootFinished();
+ getRenderEngine().setEnableTracing(mFlagManager->use_skia_tracing());
// wait patiently for the window manager death
const String16 name("window");
@@ -852,6 +851,8 @@
mCompositionEngine->getHwComposer().setCallback(*this);
ClientCache::getInstance().setRenderEngine(&getRenderEngine());
+ enableLatchUnsignaledConfig = getLatchUnsignaledConfig();
+
if (base::GetBoolProperty("debug.sf.enable_hwc_vds"s, false)) {
enableHalVirtualDisplays(true);
}
@@ -891,7 +892,7 @@
// Inform native graphics APIs whether the present timestamp is supported:
const bool presentFenceReliable =
- !getHwComposer().hasCapability(hal::Capability::PRESENT_FENCE_IS_NOT_RELIABLE);
+ !getHwComposer().hasCapability(Capability::PRESENT_FENCE_IS_NOT_RELIABLE);
mStartPropertySetThread = getFactory().createStartPropertySetThread(presentFenceReliable);
if (mStartPropertySetThread->Start() != NO_ERROR) {
@@ -955,7 +956,7 @@
};
ConditionalLock _l(mStateLock,
std::this_thread::get_id() != mMainThreadId);
- if (!getHwComposer().hasCapability(hal::Capability::PRESENT_FENCE_IS_NOT_RELIABLE)) {
+ if (!getHwComposer().hasCapability(Capability::PRESENT_FENCE_IS_NOT_RELIABLE)) {
outSupported->push_back(FrameEvent::DISPLAY_PRESENT);
}
return NO_ERROR;
@@ -1731,11 +1732,15 @@
// If we support applying display brightness as a command, then we also support
// dimming SDR layers.
if (supportsDisplayBrightnessCommand) {
- display->getCompositionDisplay()
- ->setDisplayBrightness(brightness.sdrWhitePointNits,
- brightness.displayBrightnessNits);
+ auto compositionDisplay = display->getCompositionDisplay();
+ float currentDimmingRatio =
+ compositionDisplay->editState().sdrWhitePointNits /
+ compositionDisplay->editState().displayBrightnessNits;
+ compositionDisplay->setDisplayBrightness(brightness.sdrWhitePointNits,
+ brightness.displayBrightnessNits);
MAIN_THREAD_GUARD(display->stageBrightness(brightness.displayBrightness));
- if (hasVisibleHdrLayer(display)) {
+ if (brightness.sdrWhitePointNits / brightness.displayBrightnessNits !=
+ currentDimmingRatio) {
scheduleComposite(FrameHint::kNone);
} else {
scheduleCommit(FrameHint::kNone);
@@ -1812,8 +1817,9 @@
return NO_ERROR;
}
-status_t SurfaceFlinger::getDisplayDecorationSupport(const sp<IBinder>& displayToken,
- bool* outSupport) const {
+status_t SurfaceFlinger::getDisplayDecorationSupport(
+ const sp<IBinder>& displayToken,
+ std::optional<DisplayDecorationSupport>* outSupport) const {
if (!displayToken || !outSupport) {
return BAD_VALUE;
}
@@ -1824,8 +1830,7 @@
if (!displayId) {
return NAME_NOT_FOUND;
}
- *outSupport =
- getHwComposer().hasDisplayCapability(*displayId, DisplayCapability::DISPLAY_DECORATION);
+ getHwComposer().getDisplayDecorationSupport(*displayId, outSupport);
return NO_ERROR;
}
@@ -2356,9 +2361,11 @@
// something (such as user input) to an accurate diasplay time.
// Snapping also allows an app to precisely calculate
// mVsyncConfiguration->getCurrentConfigs().late.sf with (presentLatency % interval).
- nsecs_t bias = stats.vsyncPeriod / 2;
- int64_t extraVsyncs = (compositeToPresentLatency - idealLatency + bias) / stats.vsyncPeriod;
- nsecs_t snappedCompositeToPresentLatency =
+ const nsecs_t bias = stats.vsyncPeriod / 2;
+ const int64_t extraVsyncs = (stats.vsyncPeriod) > 0 ?
+ ((compositeToPresentLatency - idealLatency + bias) / stats.vsyncPeriod) :
+ 0;
+ const nsecs_t snappedCompositeToPresentLatency =
(extraVsyncs > 0) ? idealLatency + (extraVsyncs * stats.vsyncPeriod) : idealLatency;
std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
@@ -3274,15 +3281,15 @@
continue;
}
- // There is more than one display for the layerStack. In this case, the display that is
- // configured to receive input takes precedence.
+ // There is more than one display for the layerStack. In this case, the first display that
+ // is configured to receive input takes precedence.
auto& details = it->second;
- if (!display->receivesInput()) {
+ if (details.receivesInput) {
+ ALOGW_IF(display->receivesInput(),
+ "Multiple displays claim to accept input for the same layer stack: %u",
+ layerStackId);
continue;
}
- ALOGE_IF(details.receivesInput,
- "Multiple displays claim to accept input for the same layer stack: %u",
- layerStackId);
details.receivesInput = display->receivesInput();
details.isSecure = display->isSecure();
details.transform = std::move(transform);
@@ -3377,7 +3384,7 @@
features |= Feature::kTracePredictedVsync;
}
if (!base::GetBoolProperty("debug.sf.vsync_reactor_ignore_present_fences"s, false) &&
- !getHwComposer().hasCapability(hal::Capability::PRESENT_FENCE_IS_NOT_RELIABLE)) {
+ !getHwComposer().hasCapability(Capability::PRESENT_FENCE_IS_NOT_RELIABLE)) {
features |= Feature::kPresentFences;
}
@@ -3639,6 +3646,19 @@
return old;
}
+bool SurfaceFlinger::stopTransactionProcessing(
+ const std::unordered_set<sp<IBinder>, SpHash<IBinder>>&
+ applyTokensWithUnsignaledTransactions) const {
+ if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer) {
+ // if we are in LatchUnsignaledConfig::AutoSingleLayer
+ // then we should have only one applyToken for processing.
+ // so we can stop further transactions on this applyToken.
+ return !applyTokensWithUnsignaledTransactions.empty();
+ }
+
+ return false;
+}
+
bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) {
// to prevent onHandleDestroyed from being called while the lock is held,
// we must keep a copy of the transactions (specifically the composer
@@ -3646,44 +3666,44 @@
std::vector<TransactionState> transactions;
// Layer handles that have transactions with buffers that are ready to be applied.
std::unordered_set<sp<IBinder>, SpHash<IBinder>> bufferLayersReadyToPresent;
+ std::unordered_set<sp<IBinder>, SpHash<IBinder>> applyTokensWithUnsignaledTransactions;
{
Mutex::Autolock _l(mStateLock);
{
Mutex::Autolock _l(mQueueLock);
- // allowLatchUnsignaled acts as a filter condition when latch unsignaled is either auto
- // or always. auto: in this case we let buffer latch unsignaled if we have only one
- // applyToken and if only first transaction is latch unsignaled. If more than one
- // applyToken we don't latch unsignaled.
- bool allowLatchUnsignaled = allowedLatchUnsignaled();
- bool isFirstUnsignaledTransactionApplied = false;
// Collect transactions from pending transaction queue.
auto it = mPendingTransactionQueues.begin();
while (it != mPendingTransactionQueues.end()) {
auto& [applyToken, transactionQueue] = *it;
while (!transactionQueue.empty()) {
+ if (stopTransactionProcessing(applyTokensWithUnsignaledTransactions)) {
+ ATRACE_NAME("stopTransactionProcessing");
+ break;
+ }
+
auto& transaction = transactionQueue.front();
- if (!transactionIsReadyToBeApplied(transaction.frameTimelineInfo,
- transaction.isAutoTimestamp,
- transaction.desiredPresentTime,
- transaction.originUid, transaction.states,
- bufferLayersReadyToPresent,
- allowLatchUnsignaled)) {
+ const auto ready =
+ transactionIsReadyToBeApplied(transaction.frameTimelineInfo,
+ transaction.isAutoTimestamp,
+ transaction.desiredPresentTime,
+ transaction.originUid, transaction.states,
+ bufferLayersReadyToPresent,
+ transactions.size());
+ ATRACE_INT("TransactionReadiness", static_cast<int>(ready));
+ if (ready == TransactionReadiness::NotReady) {
setTransactionFlags(eTransactionFlushNeeded);
break;
}
transaction.traverseStatesWithBuffers([&](const layer_state_t& state) {
bufferLayersReadyToPresent.insert(state.surface);
});
+ const bool appliedUnsignaled = (ready == TransactionReadiness::ReadyUnsignaled);
+ if (appliedUnsignaled) {
+ applyTokensWithUnsignaledTransactions.insert(transaction.applyToken);
+ }
+
transactions.emplace_back(std::move(transaction));
transactionQueue.pop();
- if (allowLatchUnsignaled &&
- enableLatchUnsignaledConfig == LatchUnsignaledConfig::Auto) {
- // if allowLatchUnsignaled && we are in LatchUnsignaledConfig::Auto
- // then we should have only one applyToken for processing.
- // so we can stop further transactions on this applyToken.
- isFirstUnsignaledTransactionApplied = true;
- break;
- }
}
if (transactionQueue.empty()) {
@@ -3701,25 +3721,35 @@
// Case 3: others are the transactions that are ready to apply.
while (!mTransactionQueue.empty()) {
auto& transaction = mTransactionQueue.front();
- bool pendingTransactions = mPendingTransactionQueues.find(transaction.applyToken) !=
+ const bool pendingTransactions =
+ mPendingTransactionQueues.find(transaction.applyToken) !=
mPendingTransactionQueues.end();
- if (isFirstUnsignaledTransactionApplied || pendingTransactions ||
- !transactionIsReadyToBeApplied(transaction.frameTimelineInfo,
- transaction.isAutoTimestamp,
- transaction.desiredPresentTime,
- transaction.originUid, transaction.states,
- bufferLayersReadyToPresent,
- allowLatchUnsignaled)) {
+ const auto ready = [&]() REQUIRES(mStateLock) {
+ if (pendingTransactions ||
+ stopTransactionProcessing(applyTokensWithUnsignaledTransactions)) {
+ ATRACE_NAME("pendingTransactions || stopTransactionProcessing");
+ return TransactionReadiness::NotReady;
+ }
+
+ return transactionIsReadyToBeApplied(transaction.frameTimelineInfo,
+ transaction.isAutoTimestamp,
+ transaction.desiredPresentTime,
+ transaction.originUid, transaction.states,
+ bufferLayersReadyToPresent,
+ transactions.size());
+ }();
+ ATRACE_INT("TransactionReadiness", static_cast<int>(ready));
+ if (ready == TransactionReadiness::NotReady) {
mPendingTransactionQueues[transaction.applyToken].push(std::move(transaction));
} else {
transaction.traverseStatesWithBuffers([&](const layer_state_t& state) {
bufferLayersReadyToPresent.insert(state.surface);
});
- transactions.emplace_back(std::move(transaction));
- if (allowLatchUnsignaled &&
- enableLatchUnsignaledConfig == LatchUnsignaledConfig::Auto) {
- isFirstUnsignaledTransactionApplied = true;
+ const bool appliedUnsignaled = (ready == TransactionReadiness::ReadyUnsignaled);
+ if (appliedUnsignaled) {
+ applyTokensWithUnsignaledTransactions.insert(transaction.applyToken);
}
+ transactions.emplace_back(std::move(transaction));
}
mTransactionQueue.pop_front();
ATRACE_INT("TransactionQueue", mTransactionQueue.size());
@@ -3734,7 +3764,7 @@
int64_t vsyncId) {
bool needsTraversal = false;
// Now apply all transactions.
- for (const auto& transaction : transactions) {
+ for (auto& transaction : transactions) {
needsTraversal |=
applyTransactionState(transaction.frameTimelineInfo, transaction.states,
transaction.displays, transaction.flags,
@@ -3756,62 +3786,6 @@
return needsTraversal;
}
-bool SurfaceFlinger::allowedLatchUnsignaled() {
- if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Disabled) {
- return false;
- }
- // Always mode matches the current latch unsignaled behavior.
- // This behavior is currently used by the partners and we would like
- // to keep it until we are completely migrated to Auto mode successfully
- // and we we have our fallback based implementation in place.
- if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Always) {
- return true;
- }
-
- // if enableLatchUnsignaledConfig == LatchUnsignaledConfig::Auto
- // we don't latch unsignaled if more than one applyToken, as it can backpressure
- // the other transactions.
- if (mPendingTransactionQueues.size() > 1) {
- return false;
- }
- std::optional<sp<IBinder>> applyToken = std::nullopt;
- bool isPendingTransactionQueuesItem = false;
- if (!mPendingTransactionQueues.empty()) {
- applyToken = mPendingTransactionQueues.begin()->first;
- isPendingTransactionQueuesItem = true;
- }
-
- for (const auto& item : mTransactionQueue) {
- if (!applyToken.has_value()) {
- applyToken = item.applyToken;
- } else if (applyToken.has_value() && applyToken != item.applyToken) {
- return false;
- }
- }
-
- if (isPendingTransactionQueuesItem) {
- return checkTransactionCanLatchUnsignaled(
- mPendingTransactionQueues.begin()->second.front());
- } else if (applyToken.has_value()) {
- return checkTransactionCanLatchUnsignaled((mTransactionQueue.front()));
- }
- return false;
-}
-
-bool SurfaceFlinger::checkTransactionCanLatchUnsignaled(const TransactionState& transaction) {
- if (transaction.states.size() == 1) {
- const auto& state = transaction.states.begin()->state;
- if ((state.flags & ~layer_state_t::eBufferChanged) == 0 &&
- state.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged) &&
- state.bufferData->acquireFence &&
- state.bufferData->acquireFence->getStatus() == Fence::Status::Unsignaled) {
- ATRACE_NAME("transactionCanLatchUnsignaled");
- return true;
- }
- }
- return false;
-}
-
bool SurfaceFlinger::transactionFlushNeeded() {
Mutex::Autolock _l(mQueueLock);
return !mPendingTransactionQueues.empty() || !mTransactionQueue.empty();
@@ -3838,12 +3812,57 @@
return prediction->presentTime >= expectedPresentTime &&
prediction->presentTime - expectedPresentTime >= earlyLatchVsyncThreshold;
}
+bool SurfaceFlinger::shouldLatchUnsignaled(const sp<Layer>& layer, const layer_state_t& state,
+ size_t numStates, size_t totalTXapplied) const {
+ if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Disabled) {
+ ALOGV("%s: false (LatchUnsignaledConfig::Disabled)", __func__);
+ return false;
+ }
-bool SurfaceFlinger::transactionIsReadyToBeApplied(
+ if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Always) {
+ ALOGV("%s: true (LatchUnsignaledConfig::Always)", __func__);
+ return true;
+ }
+
+ // We only want to latch unsignaled when a single layer is updated in this
+ // transaction (i.e. not a blast sync transaction).
+ if (numStates != 1) {
+ ALOGV("%s: false (numStates=%zu)", __func__, numStates);
+ return false;
+ }
+
+ if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer) {
+ if (totalTXapplied > 0) {
+ ALOGV("%s: false (LatchUnsignaledConfig::AutoSingleLayer; totalTXapplied=%zu)",
+ __func__, totalTXapplied);
+ return false;
+ }
+
+ // We don't want to latch unsignaled if are in early / client composition
+ // as it leads to jank due to RenderEngine waiting for unsignaled buffer
+ // or window animations being slow.
+ const auto isDefaultVsyncConfig = mVsyncModulator->isVsyncConfigDefault();
+ if (!isDefaultVsyncConfig) {
+ ALOGV("%s: false (LatchUnsignaledConfig::AutoSingleLayer; !isDefaultVsyncConfig)",
+ __func__);
+ return false;
+ }
+ }
+
+ if (!layer->simpleBufferUpdate(state)) {
+ ALOGV("%s: false (!simpleBufferUpdate)", __func__);
+ return false;
+ }
+
+ ALOGV("%s: true", __func__);
+ return true;
+}
+
+auto SurfaceFlinger::transactionIsReadyToBeApplied(
const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime,
uid_t originUid, const Vector<ComposerState>& states,
const std::unordered_set<sp<IBinder>, SpHash<IBinder>>& bufferLayersReadyToPresent,
- bool allowLatchUnsignaled) const {
+ size_t totalTXapplied) const -> TransactionReadiness {
ATRACE_FORMAT("transactionIsReadyToBeApplied vsyncId: %" PRId64, info.vsyncId);
const nsecs_t expectedPresentTime = mExpectedPresentTime.load();
// Do not present if the desiredPresentTime has not passed unless it is more than one second
@@ -3851,31 +3870,24 @@
if (!isAutoTimestamp && desiredPresentTime >= expectedPresentTime &&
desiredPresentTime < expectedPresentTime + s2ns(1)) {
ATRACE_NAME("not current");
- return false;
+ return TransactionReadiness::NotReady;
}
if (!mScheduler->isVsyncValid(expectedPresentTime, originUid)) {
ATRACE_NAME("!isVsyncValid");
- return false;
+ return TransactionReadiness::NotReady;
}
// If the client didn't specify desiredPresentTime, use the vsyncId to determine the expected
// present time of this transaction.
if (isAutoTimestamp && frameIsEarly(expectedPresentTime, info.vsyncId)) {
ATRACE_NAME("frameIsEarly");
- return false;
+ return TransactionReadiness::NotReady;
}
+ bool fenceUnsignaled = false;
for (const ComposerState& state : states) {
const layer_state_t& s = state.state;
- const bool acquireFenceChanged = s.bufferData &&
- s.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged);
- if (acquireFenceChanged && s.bufferData->acquireFence && !allowLatchUnsignaled &&
- s.bufferData->acquireFence->getStatus() == Fence::Status::Unsignaled) {
- ATRACE_NAME("fence unsignaled");
- return false;
- }
-
sp<Layer> layer = nullptr;
if (s.surface) {
layer = fromHandle(s.surface).promote();
@@ -3887,7 +3899,22 @@
continue;
}
- ATRACE_NAME(layer->getName().c_str());
+ const bool allowLatchUnsignaled =
+ shouldLatchUnsignaled(layer, s, states.size(), totalTXapplied);
+ ATRACE_FORMAT("%s allowLatchUnsignaled=%s", layer->getName().c_str(),
+ allowLatchUnsignaled ? "true" : "false");
+
+ const bool acquireFenceChanged = s.bufferData &&
+ s.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged) &&
+ s.bufferData->acquireFence;
+ fenceUnsignaled = fenceUnsignaled ||
+ (acquireFenceChanged &&
+ s.bufferData->acquireFence->getStatus() == Fence::Status::Unsignaled);
+
+ if (fenceUnsignaled && !allowLatchUnsignaled) {
+ ATRACE_NAME("fence unsignaled");
+ return TransactionReadiness::NotReady;
+ }
if (s.hasBufferChanges()) {
// If backpressure is enabled and we already have a buffer to commit, keep the
@@ -3896,11 +3923,11 @@
bufferLayersReadyToPresent.find(s.surface) != bufferLayersReadyToPresent.end();
if (layer->backpressureEnabled() && hasPendingBuffer && isAutoTimestamp) {
ATRACE_NAME("hasPendingBuffer");
- return false;
+ return TransactionReadiness::NotReady;
}
}
}
- return true;
+ return fenceUnsignaled ? TransactionReadiness::ReadyUnsignaled : TransactionReadiness::Ready;
}
void SurfaceFlinger::queueTransaction(TransactionState& state) {
@@ -4027,7 +4054,7 @@
}
bool SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelineInfo,
- const Vector<ComposerState>& states,
+ Vector<ComposerState>& states,
const Vector<DisplayState>& displays, uint32_t flags,
const InputWindowCommands& inputWindowCommands,
const int64_t desiredPresentTime, bool isAutoTimestamp,
@@ -4049,9 +4076,9 @@
}
uint32_t clientStateFlags = 0;
- for (const ComposerState& state : states) {
- ComposerState stateCopy = state;
- clientStateFlags |= setClientStateLocked(frameTimelineInfo, stateCopy, desiredPresentTime,
+ for (int i = 0; i < states.size(); i++) {
+ ComposerState& state = states.editItemAt(i);
+ clientStateFlags |= setClientStateLocked(frameTimelineInfo, state, desiredPresentTime,
isAutoTimestamp, postTime, permissions);
if ((flags & eAnimation) && state.state.surface) {
if (const auto layer = fromHandle(state.state.surface).promote()) {
@@ -5087,11 +5114,9 @@
}
LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const {
- const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
-
LayersProto layersProto;
for (const sp<Layer>& layer : mDrawingState.layersSortedByZ) {
- layer->writeToProto(layersProto, traceFlags, display.get());
+ layer->writeToProto(layersProto, traceFlags);
}
return layersProto;
@@ -5132,8 +5157,7 @@
rootProto->add_children(offscreenLayer->sequence);
// Add layer
- LayerProto* layerProto =
- offscreenLayer->writeToProto(layersProto, traceFlags, nullptr /*device*/);
+ LayerProto* layerProto = offscreenLayer->writeToProto(layersProto, traceFlags);
layerProto->set_parent(offscreenRootLayerId);
}
}
@@ -5507,7 +5531,13 @@
}
return PERMISSION_DENIED;
}
- case SET_OVERRIDE_FRAME_RATE:
+ case SET_OVERRIDE_FRAME_RATE: {
+ const int uid = IPCThreadState::self()->getCallingUid();
+ if (uid == AID_ROOT || uid == AID_SYSTEM) {
+ return OK;
+ }
+ return PERMISSION_DENIED;
+ }
case ON_PULL_ATOM: {
const int uid = IPCThreadState::self()->getCallingUid();
if (uid == AID_SYSTEM) {
@@ -5722,9 +5752,9 @@
}
case 1025: { // Set layer tracing
n = data.readInt32();
- int64_t fixedStartingTime = data.readInt64();
bool tracingEnabledChanged;
- if (n) {
+ if (n == 1) {
+ int64_t fixedStartingTime = data.readInt64();
ALOGD("LayerTracing enabled");
tracingEnabledChanged = mLayerTracing.enable();
if (tracingEnabledChanged) {
@@ -5736,6 +5766,10 @@
})
.wait();
}
+ } else if (n == 2) {
+ std::string filename = std::string(data.readCString());
+ ALOGD("LayerTracing disabled. Trace wrote to %s", filename.c_str());
+ tracingEnabledChanged = mLayerTracing.disable(filename.c_str());
} else {
ALOGD("LayerTracing disabled");
tracingEnabledChanged = mLayerTracing.disable();
@@ -5988,9 +6022,9 @@
mTransactionTracing->setBufferSize(
TransactionTracing::ACTIVE_TRACING_BUFFER_SIZE);
} else {
+ mTransactionTracing->writeToFile();
mTransactionTracing->setBufferSize(
TransactionTracing::CONTINUOUS_TRACING_BUFFER_SIZE);
- mTransactionTracing->writeToFile();
}
}
reply->writeInt32(NO_ERROR);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 1b8f62a..3ecce33 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -85,6 +85,8 @@
#include <unordered_set>
#include <utility>
+#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
+
using namespace android::surfaceflinger;
namespace android {
@@ -137,7 +139,20 @@
eTransactionMask = 0x1f,
};
-enum class LatchUnsignaledConfig { Always, Auto, Disabled };
+// Latch Unsignaled buffer behaviours
+enum class LatchUnsignaledConfig {
+ // All buffers are latched signaled.
+ Disabled,
+
+ // Latch unsignaled is permitted when a single layer is updated in a frame,
+ // and the update includes just a buffer update (i.e. no sync transactions
+ // or geometry changes).
+ AutoSingleLayer,
+
+ // All buffers are latched unsignaled. This behaviour is discouraged as it
+ // can break sync transactions, stall the display and cause undesired side effects.
+ Always,
+};
using DisplayColorSetting = compositionengine::OutputColorSetting;
@@ -162,6 +177,11 @@
std::atomic<nsecs_t> mLastSwapTime = 0;
};
+struct SCOPED_CAPABILITY UnnecessaryLock {
+ explicit UnnecessaryLock(Mutex& mutex) ACQUIRE(mutex) {}
+ ~UnnecessaryLock() RELEASE() {}
+};
+
class SurfaceFlinger : public BnSurfaceComposer,
public PriorityDumper,
private IBinder::DeathRecipient,
@@ -596,8 +616,10 @@
status_t notifyPowerBoost(int32_t boostId) override;
status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
float lightPosY, float lightPosZ, float lightRadius) override;
- status_t getDisplayDecorationSupport(const sp<IBinder>& displayToken,
- bool* outSupport) const override;
+ status_t getDisplayDecorationSupport(
+ const sp<IBinder>& displayToken,
+ std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
+ outSupport) const override;
status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
int8_t compatibility, int8_t changeFrameRateStrategy) override;
@@ -714,7 +736,7 @@
/*
* Transactions
*/
- bool applyTransactionState(const FrameTimelineInfo& info, const Vector<ComposerState>& state,
+ bool applyTransactionState(const FrameTimelineInfo& info, Vector<ComposerState>& state,
const Vector<DisplayState>& displays, uint32_t flags,
const InputWindowCommands& inputWindowCommands,
const int64_t desiredPresentTime, bool isAutoTimestamp,
@@ -749,16 +771,21 @@
uint32_t setTransactionFlags(uint32_t mask, TransactionSchedule,
const sp<IBinder>& applyToken = {});
void commitOffscreenLayers();
- bool transactionIsReadyToBeApplied(
+ enum class TransactionReadiness {
+ NotReady,
+ Ready,
+ ReadyUnsignaled,
+ };
+ TransactionReadiness transactionIsReadyToBeApplied(
const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime,
uid_t originUid, const Vector<ComposerState>& states,
const std::unordered_set<sp<IBinder>, SpHash<IBinder>>& bufferLayersReadyToPresent,
- bool allowLatchUnsignaled) const REQUIRES(mStateLock);
+ size_t totalTXapplied) const REQUIRES(mStateLock);
static LatchUnsignaledConfig getLatchUnsignaledConfig();
- bool latchUnsignaledIsAllowed(std::vector<TransactionState>& transactions) REQUIRES(mStateLock);
- bool allowedLatchUnsignaled() REQUIRES(mQueueLock, mStateLock);
- bool checkTransactionCanLatchUnsignaled(const TransactionState& transaction)
- REQUIRES(mStateLock);
+ bool shouldLatchUnsignaled(const sp<Layer>& layer, const layer_state_t&, size_t numStates,
+ size_t totalTXapplied) const;
+ bool stopTransactionProcessing(const std::unordered_set<sp<IBinder>, SpHash<IBinder>>&
+ applyTokensWithUnsignaledTransactions) const;
bool applyTransactions(std::vector<TransactionState>& transactions, int64_t vsyncId)
REQUIRES(mStateLock);
uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock);
@@ -1261,6 +1288,7 @@
ui::Dataspace mDefaultCompositionDataspace;
ui::Dataspace mWideColorGamutCompositionDataspace;
ui::Dataspace mColorSpaceAgnosticDataspace;
+ float mDimmingRatio = -1.f;
SurfaceFlingerBE mBE;
std::unique_ptr<compositionengine::CompositionEngine> mCompositionEngine;
diff --git a/services/surfaceflinger/Tracing/LayerTracing.cpp b/services/surfaceflinger/Tracing/LayerTracing.cpp
index 006efdf..49554c7 100644
--- a/services/surfaceflinger/Tracing/LayerTracing.cpp
+++ b/services/surfaceflinger/Tracing/LayerTracing.cpp
@@ -45,14 +45,14 @@
return true;
}
-bool LayerTracing::disable() {
+bool LayerTracing::disable(std::string filename) {
std::scoped_lock lock(mTraceLock);
if (!mEnabled) {
return false;
}
mEnabled = false;
LayersTraceFileProto fileProto = createTraceFileProto();
- mBuffer->writeToFile(fileProto, FILE_NAME);
+ mBuffer->writeToFile(fileProto, filename);
mBuffer->reset();
return true;
}
diff --git a/services/surfaceflinger/Tracing/LayerTracing.h b/services/surfaceflinger/Tracing/LayerTracing.h
index bd448c9..88a19ec 100644
--- a/services/surfaceflinger/Tracing/LayerTracing.h
+++ b/services/surfaceflinger/Tracing/LayerTracing.h
@@ -43,7 +43,7 @@
LayerTracing(SurfaceFlinger& flinger);
~LayerTracing();
bool enable();
- bool disable();
+ bool disable(std::string filename = FILE_NAME);
bool isEnabled() const;
status_t writeToFile();
LayersTraceFileProto createTraceFileProto() const;
diff --git a/services/surfaceflinger/Tracing/RingBuffer.h b/services/surfaceflinger/Tracing/RingBuffer.h
index 3b2626d..7e38c55 100644
--- a/services/surfaceflinger/Tracing/RingBuffer.h
+++ b/services/surfaceflinger/Tracing/RingBuffer.h
@@ -67,7 +67,7 @@
// -rw-r--r--
const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
if (!android::base::WriteStringToFile(output, filename, mode, getuid(), getgid(), true)) {
- ALOGE("Could not save the proto file.");
+ ALOGE("Could not save the proto file %s", filename.c_str());
return PERMISSION_DENIED;
}
return NO_ERROR;
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
index a91698f..1e5c3e7 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
@@ -22,9 +22,7 @@
namespace android::surfaceflinger {
-proto::TransactionState TransactionProtoParser::toProto(const TransactionState& t,
- LayerHandleToIdFn getLayerId,
- DisplayHandleToIdFn getDisplayId) {
+proto::TransactionState TransactionProtoParser::toProto(const TransactionState& t) {
proto::TransactionState proto;
proto.set_pid(t.originPid);
proto.set_uid(t.originUid);
@@ -33,12 +31,14 @@
proto.set_post_time(t.postTime);
proto.set_transaction_id(t.id);
+ proto.mutable_layer_changes()->Reserve(static_cast<int32_t>(t.states.size()));
for (auto& layerState : t.states) {
- proto.mutable_layer_changes()->Add(std::move(toProto(layerState.state, getLayerId)));
+ proto.mutable_layer_changes()->Add(std::move(toProto(layerState.state)));
}
+ proto.mutable_display_changes()->Reserve(static_cast<int32_t>(t.displays.size()));
for (auto& displayState : t.displays) {
- proto.mutable_display_changes()->Add(std::move(toProto(displayState, getDisplayId)));
+ proto.mutable_display_changes()->Add(std::move(toProto(displayState)));
}
return proto;
}
@@ -46,8 +46,9 @@
proto::TransactionState TransactionProtoParser::toProto(
const std::map<int32_t /* layerId */, TracingLayerState>& states) {
proto::TransactionState proto;
+ proto.mutable_layer_changes()->Reserve(static_cast<int32_t>(states.size()));
for (auto& [layerId, state] : states) {
- proto::LayerState layerProto = toProto(state, nullptr);
+ proto::LayerState layerProto = toProto(state);
if (layerProto.has_buffer_data()) {
proto::LayerState_BufferData* bufferProto = layerProto.mutable_buffer_data();
bufferProto->set_buffer_id(state.bufferId);
@@ -69,11 +70,10 @@
return proto;
}
-proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer,
- LayerHandleToIdFn getLayerId) {
+proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer) {
proto::LayerState proto;
- if (getLayerId != nullptr) {
- proto.set_layer_id(getLayerId(layer.surface));
+ if (layer.surface) {
+ proto.set_layer_id(mMapper->getLayerId(layer.surface));
} else {
proto.set_layer_id(layer.layerId);
}
@@ -136,13 +136,27 @@
}
if (layer.what & layer_state_t::eBufferChanged) {
proto::LayerState_BufferData* bufferProto = proto.mutable_buffer_data();
- if (layer.bufferData->buffer) {
+ if (layer.bufferData->hasBuffer()) {
bufferProto->set_buffer_id(layer.bufferData->getId());
bufferProto->set_width(layer.bufferData->getWidth());
bufferProto->set_height(layer.bufferData->getHeight());
bufferProto->set_pixel_format(static_cast<proto::LayerState_BufferData_PixelFormat>(
layer.bufferData->getPixelFormat()));
bufferProto->set_usage(layer.bufferData->getUsage());
+ } else {
+ uint64_t bufferId;
+ uint32_t width;
+ uint32_t height;
+ int32_t pixelFormat;
+ uint64_t usage;
+ mMapper->getGraphicBufferPropertiesFromCache(layer.bufferData->cachedBuffer, &bufferId,
+ &width, &height, &pixelFormat, &usage);
+ bufferProto->set_buffer_id(bufferId);
+ bufferProto->set_width(width);
+ bufferProto->set_height(height);
+ bufferProto->set_pixel_format(
+ static_cast<proto::LayerState_BufferData_PixelFormat>(pixelFormat));
+ bufferProto->set_usage(usage);
}
bufferProto->set_frame_number(layer.bufferData->frameNumber);
bufferProto->set_flags(layer.bufferData->flags.get());
@@ -165,15 +179,15 @@
}
}
- if ((layer.what & layer_state_t::eReparent) && getLayerId != nullptr) {
+ if (layer.what & layer_state_t::eReparent) {
int32_t layerId = layer.parentSurfaceControlForChild
- ? getLayerId(layer.parentSurfaceControlForChild->getHandle())
+ ? mMapper->getLayerId(layer.parentSurfaceControlForChild->getHandle())
: -1;
proto.set_parent_id(layerId);
}
- if ((layer.what & layer_state_t::eRelativeLayerChanged) && getLayerId != nullptr) {
+ if (layer.what & layer_state_t::eRelativeLayerChanged) {
int32_t layerId = layer.relativeLayerSurfaceControl
- ? getLayerId(layer.relativeLayerSurfaceControl->getHandle())
+ ? mMapper->getLayerId(layer.relativeLayerSurfaceControl->getHandle())
: -1;
proto.set_relative_parent_id(layerId);
proto.set_z(layer.z);
@@ -183,13 +197,16 @@
if (layer.windowInfoHandle) {
const gui::WindowInfo* inputInfo = layer.windowInfoHandle->getInfo();
proto::LayerState_WindowInfo* windowInfoProto = proto.mutable_window_info_handle();
- windowInfoProto->set_layout_params_flags(inputInfo->flags.get());
- windowInfoProto->set_layout_params_type(static_cast<int32_t>(inputInfo->type));
+ windowInfoProto->set_layout_params_flags(inputInfo->layoutParamsFlags.get());
+ windowInfoProto->set_layout_params_type(
+ static_cast<int32_t>(inputInfo->layoutParamsType));
LayerProtoHelper::writeToProto(inputInfo->touchableRegion,
windowInfoProto->mutable_touchable_region());
windowInfoProto->set_surface_inset(inputInfo->surfaceInset);
- windowInfoProto->set_focusable(inputInfo->focusable);
- windowInfoProto->set_has_wallpaper(inputInfo->hasWallpaper);
+ windowInfoProto->set_focusable(
+ !inputInfo->inputConfig.test(gui::WindowInfo::InputConfig::NOT_FOCUSABLE));
+ windowInfoProto->set_has_wallpaper(inputInfo->inputConfig.test(
+ gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER));
windowInfoProto->set_global_scale_factor(inputInfo->globalScaleFactor);
proto::LayerState_Transform* transformProto = windowInfoProto->mutable_transform();
transformProto->set_dsdx(inputInfo->transform.dsdx());
@@ -200,12 +217,8 @@
transformProto->set_ty(inputInfo->transform.ty());
windowInfoProto->set_replace_touchable_region_with_crop(
inputInfo->replaceTouchableRegionWithCrop);
- if (getLayerId != nullptr) {
- windowInfoProto->set_crop_layer_id(
- getLayerId(inputInfo->touchableRegionCropHandle.promote()));
- } else {
- windowInfoProto->set_crop_layer_id(-1);
- }
+ windowInfoProto->set_crop_layer_id(
+ mMapper->getLayerId(inputInfo->touchableRegionCropHandle.promote()));
}
}
if (layer.what & layer_state_t::eBackgroundColorChanged) {
@@ -252,13 +265,10 @@
return proto;
}
-proto::DisplayState TransactionProtoParser::toProto(const DisplayState& display,
- DisplayHandleToIdFn getDisplayId) {
+proto::DisplayState TransactionProtoParser::toProto(const DisplayState& display) {
proto::DisplayState proto;
proto.set_what(display.what);
- if (getDisplayId != nullptr) {
- proto.set_id(getDisplayId(display.token));
- }
+ proto.set_id(mMapper->getDisplayId(display.token));
if (display.what & DisplayState::eLayerStackChanged) {
proto.set_layer_stack(display.layerStack.id);
@@ -290,9 +300,7 @@
return proto;
}
-TransactionState TransactionProtoParser::fromProto(const proto::TransactionState& proto,
- LayerIdToHandleFn getLayerHandle,
- DisplayIdToHandleFn getDisplayHandle) {
+TransactionState TransactionProtoParser::fromProto(const proto::TransactionState& proto) {
TransactionState t;
t.originPid = proto.pid();
t.originUid = proto.uid();
@@ -306,14 +314,14 @@
for (int i = 0; i < layerCount; i++) {
ComposerState s;
s.state.what = 0;
- fromProto(proto.layer_changes(i), getLayerHandle, s.state);
+ fromProto(proto.layer_changes(i), s.state);
t.states.add(s);
}
int32_t displayCount = proto.display_changes_size();
t.displays.reserve(static_cast<size_t>(displayCount));
for (int i = 0; i < displayCount; i++) {
- t.displays.add(fromProto(proto.display_changes(i), getDisplayHandle));
+ t.displays.add(fromProto(proto.display_changes(i)));
}
return t;
}
@@ -328,10 +336,9 @@
}
void TransactionProtoParser::mergeFromProto(const proto::LayerState& proto,
- LayerIdToHandleFn getLayerHandle,
TracingLayerState& outState) {
layer_state_t state;
- fromProto(proto, getLayerHandle, state);
+ fromProto(proto, state);
outState.merge(state);
if (state.what & layer_state_t::eReparent) {
@@ -356,14 +363,10 @@
}
}
-void TransactionProtoParser::fromProto(const proto::LayerState& proto,
- LayerIdToHandleFn getLayerHandle, layer_state_t& layer) {
+void TransactionProtoParser::fromProto(const proto::LayerState& proto, layer_state_t& layer) {
layer.layerId = proto.layer_id();
layer.what |= proto.what();
-
- if (getLayerHandle != nullptr) {
- layer.surface = getLayerHandle(layer.layerId);
- }
+ layer.surface = mMapper->getLayerHandle(layer.layerId);
if (proto.what() & layer_state_t::ePositionChanged) {
layer.x = proto.x();
@@ -420,10 +423,11 @@
LayerProtoHelper::readFromProto(proto.crop(), layer.crop);
}
if (proto.what() & layer_state_t::eBufferChanged) {
- if (!layer.bufferData) {
- layer.bufferData = std::make_shared<BufferData>();
- }
const proto::LayerState_BufferData& bufferProto = proto.buffer_data();
+ layer.bufferData =
+ std::move(mMapper->getGraphicData(bufferProto.buffer_id(), bufferProto.width(),
+ bufferProto.height(), bufferProto.pixel_format(),
+ bufferProto.usage()));
layer.bufferData->frameNumber = bufferProto.frame_number();
layer.bufferData->flags = Flags<BufferData::BufferDataChange>(bufferProto.flags());
layer.bufferData->cachedBuffer.id = bufferProto.cached_buffer_id();
@@ -445,24 +449,24 @@
}
}
- if ((proto.what() & layer_state_t::eReparent) && (getLayerHandle != nullptr)) {
+ if (proto.what() & layer_state_t::eReparent) {
int32_t layerId = proto.parent_id();
if (layerId == -1) {
layer.parentSurfaceControlForChild = nullptr;
} else {
layer.parentSurfaceControlForChild =
- new SurfaceControl(SurfaceComposerClient::getDefault(), getLayerHandle(layerId),
- nullptr, layerId);
+ new SurfaceControl(SurfaceComposerClient::getDefault(),
+ mMapper->getLayerHandle(layerId), nullptr, layerId);
}
}
if (proto.what() & layer_state_t::eRelativeLayerChanged) {
int32_t layerId = proto.relative_parent_id();
if (layerId == -1) {
layer.relativeLayerSurfaceControl = nullptr;
- } else if (getLayerHandle != nullptr) {
+ } else {
layer.relativeLayerSurfaceControl =
- new SurfaceControl(SurfaceComposerClient::getDefault(), getLayerHandle(layerId),
- nullptr, layerId);
+ new SurfaceControl(SurfaceComposerClient::getDefault(),
+ mMapper->getLayerHandle(layerId), nullptr, layerId);
}
layer.z = proto.z();
}
@@ -471,13 +475,17 @@
gui::WindowInfo inputInfo;
const proto::LayerState_WindowInfo& windowInfoProto = proto.window_info_handle();
- inputInfo.flags = static_cast<gui::WindowInfo::Flag>(windowInfoProto.layout_params_flags());
- inputInfo.type = static_cast<gui::WindowInfo::Type>(windowInfoProto.layout_params_type());
+ inputInfo.layoutParamsFlags =
+ static_cast<gui::WindowInfo::Flag>(windowInfoProto.layout_params_flags());
+ inputInfo.layoutParamsType =
+ static_cast<gui::WindowInfo::Type>(windowInfoProto.layout_params_type());
LayerProtoHelper::readFromProto(windowInfoProto.touchable_region(),
inputInfo.touchableRegion);
inputInfo.surfaceInset = windowInfoProto.surface_inset();
- inputInfo.focusable = windowInfoProto.focusable();
- inputInfo.hasWallpaper = windowInfoProto.has_wallpaper();
+ inputInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_FOCUSABLE,
+ !windowInfoProto.focusable());
+ inputInfo.setInputConfig(gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER,
+ windowInfoProto.has_wallpaper());
inputInfo.globalScaleFactor = windowInfoProto.global_scale_factor();
const proto::LayerState_Transform& transformProto = windowInfoProto.transform();
inputInfo.transform.set(transformProto.dsdx(), transformProto.dtdx(), transformProto.dtdy(),
@@ -486,9 +494,7 @@
inputInfo.replaceTouchableRegionWithCrop =
windowInfoProto.replace_touchable_region_with_crop();
int32_t layerId = windowInfoProto.crop_layer_id();
- if (getLayerHandle != nullptr) {
- inputInfo.touchableRegionCropHandle = getLayerHandle(layerId);
- }
+ inputInfo.touchableRegionCropHandle = mMapper->getLayerHandle(layerId);
layer.windowInfoHandle = sp<gui::WindowInfoHandle>::make(inputInfo);
}
if (proto.what() & layer_state_t::eBackgroundColorChanged) {
@@ -534,13 +540,10 @@
}
}
-DisplayState TransactionProtoParser::fromProto(const proto::DisplayState& proto,
- DisplayIdToHandleFn getDisplayHandle) {
+DisplayState TransactionProtoParser::fromProto(const proto::DisplayState& proto) {
DisplayState display;
display.what = proto.what();
- if (getDisplayHandle != nullptr) {
- display.token = getDisplayHandle(proto.id());
- }
+ display.token = mMapper->getDisplayHandle(proto.id());
if (display.what & DisplayState::eLayerStackChanged) {
display.layerStack.id = proto.layer_stack();
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.h b/services/surfaceflinger/Tracing/TransactionProtoParser.h
index d589936..2f70b27 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.h
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.h
@@ -43,33 +43,77 @@
TracingLayerCreationArgs args;
};
-class TransactionProtoParser {
+// Class which exposes buffer properties from BufferData without holding on to the actual buffer
+// handle.
+class BufferDataStub : public BufferData {
public:
- typedef std::function<sp<IBinder>(int32_t)> LayerIdToHandleFn;
- typedef std::function<sp<IBinder>(int32_t)> DisplayIdToHandleFn;
- typedef std::function<int32_t(const sp<IBinder>&)> LayerHandleToIdFn;
- typedef std::function<int32_t(const sp<IBinder>&)> DisplayHandleToIdFn;
-
- static proto::TransactionState toProto(const TransactionState&, LayerHandleToIdFn getLayerIdFn,
- DisplayHandleToIdFn getDisplayIdFn);
- static proto::TransactionState toProto(
- const std::map<int32_t /* layerId */, TracingLayerState>&);
-
- static proto::LayerCreationArgs toProto(const TracingLayerCreationArgs& args);
-
- static TransactionState fromProto(const proto::TransactionState&,
- LayerIdToHandleFn getLayerHandleFn,
- DisplayIdToHandleFn getDisplayHandleFn);
- static void mergeFromProto(const proto::LayerState&, LayerIdToHandleFn getLayerHandleFn,
- TracingLayerState& outState);
- static void fromProto(const proto::LayerCreationArgs&, TracingLayerCreationArgs& outArgs);
+ BufferDataStub(uint64_t bufferId, uint32_t width, uint32_t height, int32_t pixelFormat,
+ uint64_t outUsage)
+ : mBufferId(bufferId),
+ mWidth(width),
+ mHeight(height),
+ mPixelFormat(pixelFormat),
+ mOutUsage(outUsage) {}
+ bool hasBuffer() const override { return mBufferId != 0; }
+ bool hasSameBuffer(const BufferData& other) const override {
+ return getId() == other.getId() && frameNumber == other.frameNumber;
+ }
+ uint32_t getWidth() const override { return mWidth; }
+ uint32_t getHeight() const override { return mHeight; }
+ uint64_t getId() const override { return mBufferId; }
+ PixelFormat getPixelFormat() const override { return mPixelFormat; }
+ uint64_t getUsage() const override { return mOutUsage; }
private:
- static proto::LayerState toProto(const layer_state_t&, LayerHandleToIdFn getLayerId);
- static proto::DisplayState toProto(const DisplayState&, DisplayHandleToIdFn getDisplayId);
- static void fromProto(const proto::LayerState&, LayerIdToHandleFn getLayerHandle,
- layer_state_t& out);
- static DisplayState fromProto(const proto::DisplayState&, DisplayIdToHandleFn getDisplayHandle);
+ uint64_t mBufferId;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ int32_t mPixelFormat;
+ uint64_t mOutUsage;
+};
+
+class TransactionProtoParser {
+public:
+ // Utility class to map handles to ids and buffers to buffer properties without pulling
+ // in SurfaceFlinger dependencies.
+ class FlingerDataMapper {
+ public:
+ virtual ~FlingerDataMapper() = default;
+ virtual sp<IBinder> getLayerHandle(int32_t /* layerId */) const { return nullptr; }
+ virtual int32_t getLayerId(const sp<IBinder>& /* layerHandle */) const { return -1; }
+ virtual sp<IBinder> getDisplayHandle(int32_t /* displayId */) const { return nullptr; }
+ virtual int32_t getDisplayId(const sp<IBinder>& /* displayHandle */) const { return -1; }
+ virtual std::shared_ptr<BufferData> getGraphicData(uint64_t bufferId, uint32_t width,
+ uint32_t height, int32_t pixelFormat,
+ uint64_t usage) const {
+ return std::make_shared<BufferDataStub>(bufferId, width, height, pixelFormat, usage);
+ }
+ virtual void getGraphicBufferPropertiesFromCache(client_cache_t /* cachedBuffer */,
+ uint64_t* /* outBufferId */,
+ uint32_t* /* outWidth */,
+ uint32_t* /* outHeight */,
+ int32_t* /* outPixelFormat */,
+ uint64_t* /* outUsage */) const {}
+ };
+
+ TransactionProtoParser(std::unique_ptr<FlingerDataMapper> provider)
+ : mMapper(std::move(provider)) {}
+
+ proto::TransactionState toProto(const TransactionState&);
+ proto::TransactionState toProto(const std::map<int32_t /* layerId */, TracingLayerState>&);
+ proto::LayerCreationArgs toProto(const TracingLayerCreationArgs& args);
+
+ TransactionState fromProto(const proto::TransactionState&);
+ void mergeFromProto(const proto::LayerState&, TracingLayerState& outState);
+ void fromProto(const proto::LayerCreationArgs&, TracingLayerCreationArgs& outArgs);
+
+private:
+ proto::LayerState toProto(const layer_state_t&);
+ proto::DisplayState toProto(const DisplayState&);
+ void fromProto(const proto::LayerState&, layer_state_t& out);
+ DisplayState fromProto(const proto::DisplayState&);
+
+ std::unique_ptr<FlingerDataMapper> mMapper;
};
} // namespace android::surfaceflinger
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.cpp b/services/surfaceflinger/Tracing/TransactionTracing.cpp
index a46b795..d5e837f 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.cpp
+++ b/services/surfaceflinger/Tracing/TransactionTracing.cpp
@@ -23,11 +23,57 @@
#include <utils/SystemClock.h>
#include <utils/Trace.h>
+#include "ClientCache.h"
#include "TransactionTracing.h"
+#include "renderengine/ExternalTexture.h"
namespace android {
-TransactionTracing::TransactionTracing() {
+class FlingerDataMapper : public TransactionProtoParser::FlingerDataMapper {
+ std::unordered_map<BBinder* /* layerHandle */, int32_t /* layerId */>& mLayerHandles;
+
+public:
+ FlingerDataMapper(std::unordered_map<BBinder* /* handle */, int32_t /* id */>& layerHandles)
+ : mLayerHandles(layerHandles) {}
+
+ int32_t getLayerId(const sp<IBinder>& layerHandle) const override {
+ if (layerHandle == nullptr) {
+ return -1;
+ }
+ auto it = mLayerHandles.find(layerHandle->localBinder());
+ if (it == mLayerHandles.end()) {
+ ALOGW("Could not find layer handle %p", layerHandle->localBinder());
+ return -1;
+ }
+ return it->second;
+ }
+
+ void getGraphicBufferPropertiesFromCache(client_cache_t cachedBuffer, uint64_t* outBufferId,
+ uint32_t* outWidth, uint32_t* outHeight,
+ int32_t* outPixelFormat,
+ uint64_t* outUsage) const override {
+ std::shared_ptr<renderengine::ExternalTexture> buffer =
+ ClientCache::getInstance().get(cachedBuffer);
+ if (!buffer || !buffer->getBuffer()) {
+ *outBufferId = 0;
+ *outWidth = 0;
+ *outHeight = 0;
+ *outPixelFormat = 0;
+ *outUsage = 0;
+ return;
+ }
+
+ *outBufferId = buffer->getId();
+ *outWidth = buffer->getWidth();
+ *outHeight = buffer->getHeight();
+ *outPixelFormat = buffer->getPixelFormat();
+ *outUsage = buffer->getUsage();
+ return;
+ }
+};
+
+TransactionTracing::TransactionTracing()
+ : mProtoParser(std::make_unique<FlingerDataMapper>(mLayerHandles)) {
std::scoped_lock lock(mTraceLock);
mBuffer.setSize(mBufferSizeInBytes);
@@ -53,11 +99,11 @@
writeToFile();
}
-status_t TransactionTracing::writeToFile() {
+status_t TransactionTracing::writeToFile(std::string filename) {
std::scoped_lock lock(mTraceLock);
proto::TransactionTraceFile fileProto = createTraceFileProto();
addStartingStateToProtoLocked(fileProto);
- return mBuffer.writeToFile(fileProto, FILE_NAME);
+ return mBuffer.writeToFile(fileProto, filename);
}
void TransactionTracing::setBufferSize(size_t bufferSizeInBytes) {
@@ -85,11 +131,7 @@
void TransactionTracing::addQueuedTransaction(const TransactionState& transaction) {
std::scoped_lock lock(mTraceLock);
ATRACE_CALL();
- mQueuedTransactions[transaction.id] =
- TransactionProtoParser::toProto(transaction,
- std::bind(&TransactionTracing::getLayerIdLocked, this,
- std::placeholders::_1),
- nullptr);
+ mQueuedTransactions[transaction.id] = mProtoParser.toProto(transaction);
}
void TransactionTracing::addCommittedTransactions(std::vector<TransactionState>& transactions,
@@ -212,9 +254,7 @@
ALOGW("Duplicate handles found. %p", layerHandle);
}
mLayerHandles[layerHandle] = layerId;
- proto::LayerCreationArgs protoArgs = TransactionProtoParser::toProto(args);
- proto::LayerCreationArgs protoArgsCopy = protoArgs;
- mCreatedLayers.push_back(protoArgs);
+ mCreatedLayers.push_back(mProtoParser.toProto(args));
}
void TransactionTracing::onMirrorLayerAdded(BBinder* layerHandle, int layerId,
@@ -225,7 +265,7 @@
ALOGW("Duplicate handles found. %p", layerHandle);
}
mLayerHandles[layerHandle] = layerId;
- mCreatedLayers.emplace_back(TransactionProtoParser::toProto(args));
+ mCreatedLayers.emplace_back(mProtoParser.toProto(args));
}
void TransactionTracing::onLayerRemoved(int32_t layerId) {
@@ -263,18 +303,6 @@
}
}
-int32_t TransactionTracing::getLayerIdLocked(const sp<IBinder>& layerHandle) {
- if (layerHandle == nullptr) {
- return -1;
- }
- auto it = mLayerHandles.find(layerHandle->localBinder());
- if (it == mLayerHandles.end()) {
- ALOGW("Could not find layer handle %p", layerHandle->localBinder());
- return -1;
- }
- return it->second;
-}
-
void TransactionTracing::updateStartingStateLocked(
const proto::TransactionTraceEntry& removedEntry) {
mStartingTimestamp = removedEntry.elapsed_realtime_nanos();
@@ -283,7 +311,7 @@
for (const proto::LayerCreationArgs& addedLayer : removedEntry.added_layers()) {
TracingLayerState& startingState = mStartingStates[addedLayer.layer_id()];
startingState.layerId = addedLayer.layer_id();
- TransactionProtoParser::fromProto(addedLayer, startingState.args);
+ mProtoParser.fromProto(addedLayer, startingState.args);
}
// Merge layer states to starting transaction state.
@@ -294,7 +322,7 @@
ALOGW("Could not find layer id %d", layerState.layer_id());
continue;
}
- TransactionProtoParser::mergeFromProto(layerState, nullptr, it->second);
+ mProtoParser.mergeFromProto(layerState, it->second);
}
}
@@ -316,10 +344,10 @@
entryProto->mutable_added_layers()->Reserve(static_cast<int32_t>(mStartingStates.size()));
for (auto& [layerId, state] : mStartingStates) {
- entryProto->mutable_added_layers()->Add(TransactionProtoParser::toProto(state.args));
+ entryProto->mutable_added_layers()->Add(mProtoParser.toProto(state.args));
}
- proto::TransactionState transactionProto = TransactionProtoParser::toProto(mStartingStates);
+ proto::TransactionState transactionProto = mProtoParser.toProto(mStartingStates);
transactionProto.set_vsync_id(0);
transactionProto.set_post_time(mStartingTimestamp);
entryProto->mutable_transactions()->Add(std::move(transactionProto));
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.h b/services/surfaceflinger/Tracing/TransactionTracing.h
index d5d98ce..95256c4 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.h
+++ b/services/surfaceflinger/Tracing/TransactionTracing.h
@@ -55,7 +55,7 @@
void addQueuedTransaction(const TransactionState&);
void addCommittedTransactions(std::vector<TransactionState>& transactions, int64_t vsyncId);
- status_t writeToFile();
+ status_t writeToFile(std::string filename = FILE_NAME);
void setBufferSize(size_t bufferSizeInBytes);
void onLayerAdded(BBinder* layerHandle, int layerId, const std::string& name, uint32_t flags,
int parentId);
@@ -84,6 +84,7 @@
GUARDED_BY(mTraceLock);
std::vector<int32_t /* layerId */> mRemovedLayerHandles GUARDED_BY(mTraceLock);
std::map<int32_t /* layerId */, TracingLayerState> mStartingStates GUARDED_BY(mTraceLock);
+ TransactionProtoParser mProtoParser GUARDED_BY(mTraceLock);
// We do not want main thread to block so main thread will try to acquire mMainThreadLock,
// otherwise will push data to temporary container.
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp
index b705d9c..e1f348f 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.cpp
+++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp
@@ -167,7 +167,7 @@
handle->gpuCompositionDoneFence->getSnapshot().fence,
handle->compositorTiming, handle->refreshStartTime,
handle->dequeueReadyTime);
- transactionStats->surfaceStats.emplace_back(surfaceControl, handle->acquireTime,
+ transactionStats->surfaceStats.emplace_back(surfaceControl, handle->acquireTimeOrFence,
handle->previousReleaseFence,
handle->transformHint,
handle->currentMaxAcquiredBufferCount,
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h
index 5ef5475..a68cd87 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.h
+++ b/services/surfaceflinger/TransactionCallbackInvoker.h
@@ -47,7 +47,7 @@
std::string name;
sp<Fence> previousReleaseFence;
std::vector<std::shared_future<renderengine::RenderEngineResult>> previousReleaseFences;
- nsecs_t acquireTime = -1;
+ std::variant<nsecs_t, sp<Fence>> acquireTimeOrFence = -1;
nsecs_t latchTime = -1;
uint32_t transformHint = 0;
uint32_t currentMaxAcquiredBufferCount = 0;
diff --git a/services/surfaceflinger/fuzzer/Android.bp b/services/surfaceflinger/fuzzer/Android.bp
index b0d216e..d2f6f71 100644
--- a/services/surfaceflinger/fuzzer/Android.bp
+++ b/services/surfaceflinger/fuzzer/Android.bp
@@ -15,6 +15,15 @@
*
*/
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "surfaceflinger_fuzz_defaults",
include_dirs: [
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
index 816d2f1..3c4ab95 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
@@ -44,6 +44,7 @@
using namespace android::hardware::graphics::common;
using namespace android::hardware::graphics::composer;
+namespace aidl = aidl::android::hardware::graphics::composer3;
namespace hal = android::hardware::graphics::composer::hal;
using Config = hal::V2_1::Config;
using Display = hal::V2_1::Display;
@@ -58,10 +59,11 @@
hal::Transform::ROT_90, hal::Transform::ROT_180,
hal::Transform::ROT_270};
-static constexpr hal::Capability kCapability[] = {hal::Capability::INVALID,
- hal::Capability::SIDEBAND_STREAM,
- hal::Capability::SKIP_CLIENT_COLOR_TRANSFORM,
- hal::Capability::PRESENT_FENCE_IS_NOT_RELIABLE};
+static constexpr aidl::Capability kCapability[] = {aidl::Capability::INVALID,
+ aidl::Capability::SIDEBAND_STREAM,
+ aidl::Capability::SKIP_CLIENT_COLOR_TRANSFORM,
+ aidl::Capability::PRESENT_FENCE_IS_NOT_RELIABLE,
+ aidl::Capability::SKIP_VALIDATE};
static constexpr hal::BlendMode kBlendModes[] = {hal::BlendMode::INVALID, hal::BlendMode::NONE,
hal::BlendMode::PREMULTIPLIED,
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
index 4f89cd9..30a6fbd 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
@@ -25,7 +25,7 @@
static constexpr LatchUnsignaledConfig kLatchUnsignaledConfig[] = {
LatchUnsignaledConfig::Always,
- LatchUnsignaledConfig::Auto,
+ LatchUnsignaledConfig::AutoSingleLayer,
LatchUnsignaledConfig::Disabled,
};
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
index 51a5081..09ffb02 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
@@ -63,8 +63,7 @@
FuzzedDataProvider mFdp;
protected:
- void onVSyncEvent(nsecs_t /* when */, nsecs_t /* expectedVSyncTimestamp */,
- nsecs_t /* deadlineTimestamp */) {}
+ void onVSyncEvent(nsecs_t /* when */, VSyncSource::VSyncData) {}
};
PhysicalDisplayId SchedulerFuzzer::getPhysicalDisplayId() {
@@ -101,8 +100,9 @@
void SchedulerFuzzer::fuzzDispSyncSource() {
std::unique_ptr<FuzzImplVSyncDispatch> vSyncDispatch =
std::make_unique<FuzzImplVSyncDispatch>();
+ std::unique_ptr<FuzzImplVSyncTracker> vSyncTracker = std::make_unique<FuzzImplVSyncTracker>();
std::unique_ptr<scheduler::DispSyncSource> dispSyncSource = std::make_unique<
- scheduler::DispSyncSource>(*vSyncDispatch,
+ scheduler::DispSyncSource>(*vSyncDispatch, *vSyncTracker,
(std::chrono::nanoseconds)
mFdp.ConsumeIntegral<uint64_t>() /*workDuration*/,
(std::chrono::nanoseconds)mFdp.ConsumeIntegral<uint64_t>()
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h
index 89cf819..84b3912 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h
@@ -103,6 +103,8 @@
void setDuration(std::chrono::nanoseconds /* workDuration */,
std::chrono::nanoseconds /* readyDuration */) override {}
+ VSyncData getLatestVSyncData() const override { return {}; }
+
void dump(std::string& /* result */) const override {}
};
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index 7b86229..efcc386 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -31,6 +31,7 @@
"Credentials_test.cpp",
"DereferenceSurfaceControl_test.cpp",
"DisplayConfigs_test.cpp",
+ "DisplayEventReceiver_test.cpp",
"EffectLayer_test.cpp",
"InvalidHandles_test.cpp",
"LayerCallback_test.cpp",
@@ -47,6 +48,7 @@
"ReleaseBufferCallback_test.cpp",
"ScreenCapture_test.cpp",
"SetFrameRate_test.cpp",
+ "SetFrameRateOverride_test.cpp",
"SetGeometry_test.cpp",
"Stress_test.cpp",
"SurfaceInterceptor_test.cpp",
diff --git a/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp b/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp
new file mode 100644
index 0000000..0e54664
--- /dev/null
+++ b/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <gui/DisplayEventReceiver.h>
+
+namespace android {
+
+class DisplayEventReceiverTest : public ::testing::Test {
+public:
+ void SetUp() override { EXPECT_EQ(NO_ERROR, mDisplayEventReceiver.initCheck()); }
+
+ DisplayEventReceiver mDisplayEventReceiver;
+};
+
+TEST_F(DisplayEventReceiverTest, getLatestVsyncEventData) {
+ const nsecs_t now = systemTime();
+ ParcelableVsyncEventData parcelableVsyncEventData;
+ EXPECT_EQ(NO_ERROR, mDisplayEventReceiver.getLatestVsyncEventData(&parcelableVsyncEventData));
+
+ const VsyncEventData& vsyncEventData = parcelableVsyncEventData.vsync;
+ EXPECT_NE(std::numeric_limits<size_t>::max(), vsyncEventData.preferredFrameTimelineIndex);
+ EXPECT_GT(vsyncEventData.frameTimelines[0].deadlineTimestamp, now)
+ << "Deadline timestamp should be greater than frame time";
+ for (size_t i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
+ EXPECT_NE(FrameTimelineInfo::INVALID_VSYNC_ID, vsyncEventData.frameTimelines[i].vsyncId);
+ EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentationTime,
+ vsyncEventData.frameTimelines[i].deadlineTimestamp)
+ << "Expected vsync timestamp should be greater than deadline";
+ if (i > 0) {
+ EXPECT_GT(vsyncEventData.frameTimelines[i].deadlineTimestamp,
+ vsyncEventData.frameTimelines[i - 1].deadlineTimestamp)
+ << "Deadline timestamp out of order for frame timeline " << i;
+ EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentationTime,
+ vsyncEventData.frameTimelines[i - 1].expectedPresentationTime)
+ << "Expected vsync timestamp out of order for frame timeline " << i;
+ }
+ }
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp
index 5c16fee..8a2305b 100644
--- a/services/surfaceflinger/tests/LayerCallback_test.cpp
+++ b/services/surfaceflinger/tests/LayerCallback_test.cpp
@@ -141,11 +141,12 @@
continue;
}
- vsync = {event.vsync.vsyncId, event.vsync.expectedVSyncTimestamp};
+ vsync = {event.vsync.vsyncData.preferredVsyncId(),
+ event.vsync.vsyncData.preferredExpectedPresentationTime()};
}
EXPECT_GE(vsync.vsyncId, 1);
- EXPECT_GT(event.vsync.expectedVSyncTimestamp, systemTime());
+ EXPECT_GT(vsync.expectedPresentTime, systemTime());
return vsync;
}
diff --git a/services/surfaceflinger/tests/SetFrameRateOverride_test.cpp b/services/surfaceflinger/tests/SetFrameRateOverride_test.cpp
new file mode 100644
index 0000000..4efec77
--- /dev/null
+++ b/services/surfaceflinger/tests/SetFrameRateOverride_test.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <gui/DisplayEventReceiver.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <sys/epoll.h>
+#include <algorithm>
+
+namespace android {
+namespace {
+using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride;
+
+class SetFrameRateOverrideTest : public ::testing::Test {
+protected:
+ void SetUp() override {
+ const ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp;
+ const ISurfaceComposer::EventRegistrationFlags eventRegistration = {
+ ISurfaceComposer::EventRegistration::frameRateOverride};
+
+ mDisplayEventReceiver =
+ std::make_unique<DisplayEventReceiver>(vsyncSource, eventRegistration);
+ EXPECT_EQ(NO_ERROR, mDisplayEventReceiver->initCheck());
+
+ mEpollFd = epoll_create1(EPOLL_CLOEXEC);
+ EXPECT_GT(mEpollFd, 1);
+
+ epoll_event event;
+ event.events = EPOLLIN;
+ EXPECT_EQ(0, epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mDisplayEventReceiver->getFd(), &event));
+ }
+
+ void TearDown() override { close(mEpollFd); }
+
+ void setFrameRateAndListenEvents(uid_t uid, float frameRate) {
+ status_t ret = SurfaceComposerClient::setOverrideFrameRate(uid, frameRate);
+ ASSERT_EQ(NO_ERROR, ret);
+
+ DisplayEventReceiver::Event event;
+ bool isOverrideFlushReceived = false;
+ mFrameRateOverrides.clear();
+
+ epoll_event epollEvent;
+ while (epoll_wait(mEpollFd, &epollEvent, 1, 1000) > 0) {
+ while (mDisplayEventReceiver->getEvents(&event, 1) > 0) {
+ if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE) {
+ mFrameRateOverrides.emplace_back(event.frameRateOverride);
+ }
+ if (event.header.type ==
+ DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH) {
+ isOverrideFlushReceived = true;
+ }
+ }
+
+ if (isOverrideFlushReceived) break;
+ }
+ }
+
+ std::unique_ptr<DisplayEventReceiver> mDisplayEventReceiver;
+ std::vector<FrameRateOverride> mFrameRateOverrides;
+
+ int mEpollFd;
+};
+
+TEST_F(SetFrameRateOverrideTest, SetFrameRateOverrideCall) {
+ uid_t uid = getuid();
+ float frameRate = 30.0f;
+ setFrameRateAndListenEvents(uid, frameRate);
+ // check if the frame rate override we set exists
+ ASSERT_TRUE(std::find_if(mFrameRateOverrides.begin(), mFrameRateOverrides.end(),
+ [uid = uid, frameRate = frameRate](auto i) {
+ return uid == i.uid && frameRate == i.frameRateHz;
+ }) != mFrameRateOverrides.end());
+
+ // test removing frame rate override
+ frameRate = 0.0f;
+ setFrameRateAndListenEvents(uid, frameRate);
+ ASSERT_TRUE(std::find_if(mFrameRateOverrides.begin(), mFrameRateOverrides.end(),
+ [uid = uid, frameRate = frameRate](auto i) {
+ return uid == i.uid && frameRate == i.frameRateHz;
+ }) == mFrameRateOverrides.end());
+}
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 48f18b9..1db5e61 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -80,6 +80,7 @@
"FpsReporterTest.cpp",
"FpsTest.cpp",
"FramebufferSurfaceTest.cpp",
+ "FrameRateOverrideMappingsTest.cpp",
"FrameTimelineTest.cpp",
"GameModeTest.cpp",
"HWComposerTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 3716f59..1669075 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -61,6 +61,8 @@
using hal::PowerMode;
using hal::Transform;
+using aidl::android::hardware::graphics::composer3::Capability;
+
using testing::_;
using testing::AtLeast;
using testing::DoAll;
@@ -169,7 +171,7 @@
template <typename Case>
void captureScreenComposition();
- std::unordered_set<hal::Capability> mDefaultCapabilities = {hal::Capability::SIDEBAND_STREAM};
+ std::unordered_set<Capability> mDefaultCapabilities = {Capability::SIDEBAND_STREAM};
bool mDisplayOff = false;
TestableSurfaceFlinger mFlinger;
diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
index f613e43..ec27eda 100644
--- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
@@ -28,6 +28,7 @@
#include "AsyncCallRecorder.h"
#include "Scheduler/DispSyncSource.h"
#include "Scheduler/VSyncDispatch.h"
+#include "mock/MockVSyncTracker.h"
namespace android {
namespace {
@@ -125,16 +126,16 @@
DispSyncSourceTest();
~DispSyncSourceTest() override;
- void createDispSync();
+ void SetUp() override;
void createDispSyncSource();
- void onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp,
- nsecs_t deadlineTimestamp) override;
+ void onVSyncEvent(nsecs_t when, VSyncSource::VSyncData) override;
std::unique_ptr<MockVSyncDispatch> mVSyncDispatch;
+ std::unique_ptr<mock::VSyncTracker> mVSyncTracker;
std::unique_ptr<scheduler::DispSyncSource> mDispSyncSource;
- AsyncCallRecorder<void (*)(nsecs_t, nsecs_t, nsecs_t)> mVSyncEventCallRecorder;
+ AsyncCallRecorder<void (*)(nsecs_t, VSyncSource::VSyncData)> mVSyncEventCallRecorder;
static constexpr std::chrono::nanoseconds mWorkDuration = 20ms;
static constexpr std::chrono::nanoseconds mReadyDuration = 10ms;
@@ -155,21 +156,21 @@
ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
}
-void DispSyncSourceTest::onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp,
- nsecs_t deadlineTimestamp) {
- ALOGD("onVSyncEvent: %" PRId64, when);
-
- mVSyncEventCallRecorder.recordCall(when, expectedVSyncTimestamp, deadlineTimestamp);
+void DispSyncSourceTest::SetUp() {
+ mVSyncDispatch = std::make_unique<MockVSyncDispatch>();
+ mVSyncTracker = std::make_unique<mock::VSyncTracker>();
}
-void DispSyncSourceTest::createDispSync() {
- mVSyncDispatch = std::make_unique<MockVSyncDispatch>();
+void DispSyncSourceTest::onVSyncEvent(nsecs_t when, VSyncSource::VSyncData vsyncData) {
+ ALOGD("onVSyncEvent: %" PRId64, when);
+
+ mVSyncEventCallRecorder.recordCall(when, vsyncData);
}
void DispSyncSourceTest::createDispSyncSource() {
- mDispSyncSource =
- std::make_unique<scheduler::DispSyncSource>(*mVSyncDispatch, mWorkDuration,
- mReadyDuration, true, mName.c_str());
+ mDispSyncSource = std::make_unique<scheduler::DispSyncSource>(*mVSyncDispatch, *mVSyncTracker,
+ mWorkDuration, mReadyDuration,
+ true, mName.c_str());
mDispSyncSource->setCallback(this);
}
@@ -178,13 +179,10 @@
*/
TEST_F(DispSyncSourceTest, createDispSync) {
- createDispSync();
EXPECT_TRUE(mVSyncDispatch);
}
TEST_F(DispSyncSourceTest, createDispSyncSource) {
- createDispSync();
-
InSequence seq;
EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).WillOnce(Return(mFakeToken));
EXPECT_CALL(*mVSyncDispatch, cancel(mFakeToken))
@@ -196,8 +194,6 @@
}
TEST_F(DispSyncSourceTest, noCallbackAfterInit) {
- createDispSync();
-
InSequence seq;
EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1);
@@ -212,8 +208,6 @@
}
TEST_F(DispSyncSourceTest, waitForCallbacks) {
- createDispSync();
-
InSequence seq;
EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
EXPECT_CALL(*mVSyncDispatch,
@@ -233,14 +227,14 @@
mVSyncDispatch->triggerCallbacks();
const auto callbackData = mVSyncEventCallRecorder.waitForCall();
ASSERT_TRUE(callbackData.has_value());
- const auto [when, expectedVSyncTimestamp, deadlineTimestamp] = callbackData.value();
- EXPECT_EQ(when, expectedVSyncTimestamp - mWorkDuration.count() - mReadyDuration.count());
+ const auto [when, vsyncData] = callbackData.value();
+ EXPECT_EQ(when,
+ vsyncData.expectedPresentationTime - mWorkDuration.count() -
+ mReadyDuration.count());
}
}
TEST_F(DispSyncSourceTest, waitForCallbacksWithDurationChange) {
- createDispSync();
-
InSequence seq;
EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
EXPECT_CALL(*mVSyncDispatch,
@@ -265,8 +259,10 @@
mVSyncDispatch->triggerCallbacks();
const auto callbackData = mVSyncEventCallRecorder.waitForCall();
ASSERT_TRUE(callbackData.has_value());
- const auto [when, expectedVSyncTimestamp, deadlineTimestamp] = callbackData.value();
- EXPECT_EQ(when, expectedVSyncTimestamp - mWorkDuration.count() - mReadyDuration.count());
+ const auto [when, vsyncData] = callbackData.value();
+ EXPECT_EQ(when,
+ vsyncData.expectedPresentationTime - mWorkDuration.count() -
+ mReadyDuration.count());
}
const auto newDuration = mWorkDuration / 2;
@@ -286,13 +282,35 @@
mVSyncDispatch->triggerCallbacks();
const auto callbackData = mVSyncEventCallRecorder.waitForCall();
ASSERT_TRUE(callbackData.has_value());
- const auto [when, expectedVSyncTimestamp, deadlineTimestamp] = callbackData.value();
- EXPECT_EQ(when, expectedVSyncTimestamp - newDuration.count());
+ const auto [when, vsyncData] = callbackData.value();
+ EXPECT_EQ(when, vsyncData.expectedPresentationTime - newDuration.count());
}
EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1);
EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1);
}
+TEST_F(DispSyncSourceTest, getLatestVsyncData) {
+ const nsecs_t now = systemTime();
+ const nsecs_t vsyncInternalDuration = mWorkDuration.count() + mReadyDuration.count();
+ EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_))
+ .WillOnce(Return(now + vsyncInternalDuration + 1));
+ {
+ InSequence seq;
+ EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
+ EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1);
+ EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1);
+ }
+
+ createDispSyncSource();
+ EXPECT_TRUE(mDispSyncSource);
+
+ const auto vsyncData = mDispSyncSource->getLatestVSyncData();
+ ASSERT_GT(vsyncData.deadlineTimestamp, now);
+ ASSERT_GT(vsyncData.expectedPresentationTime, vsyncData.deadlineTimestamp);
+ EXPECT_EQ(vsyncData.deadlineTimestamp,
+ vsyncData.expectedPresentationTime - vsyncInternalDuration);
+}
+
} // namespace
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 67a0d7e..14d8f98 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -59,6 +59,7 @@
void(std::chrono::nanoseconds workDuration,
std::chrono::nanoseconds readyDuration));
MOCK_METHOD1(pauseVsyncCallback, void(bool));
+ MOCK_METHOD(VSyncSource::VSyncData, getLatestVSyncData, (), (const, override));
MOCK_CONST_METHOD1(dump, void(std::string&));
};
@@ -98,7 +99,7 @@
nsecs_t expectedTimestamp, unsigned expectedCount);
void expectVsyncEventReceivedByConnection(nsecs_t expectedTimestamp, unsigned expectedCount);
void expectVsyncEventFrameTimelinesCorrect(nsecs_t expectedTimestamp,
- nsecs_t preferredDeadline);
+ VSyncSource::VSyncData preferredVsyncData);
void expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
bool expectedConnected);
void expectConfigChangedEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
@@ -251,41 +252,42 @@
expectedCount);
}
-void EventThreadTest::expectVsyncEventFrameTimelinesCorrect(nsecs_t expectedTimestamp,
- nsecs_t preferredDeadline) {
+void EventThreadTest::expectVsyncEventFrameTimelinesCorrect(
+ nsecs_t expectedTimestamp, VSyncSource::VSyncData preferredVsyncData) {
auto args = mConnectionEventCallRecorder.waitForCall();
ASSERT_TRUE(args.has_value()) << " did not receive an event for timestamp "
<< expectedTimestamp;
const auto& event = std::get<0>(args.value());
- for (int i = 0; i < DisplayEventReceiver::kFrameTimelinesLength; i++) {
- auto prediction =
- mTokenManager->getPredictionsForToken(event.vsync.frameTimelines[i].vsyncId);
+ for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
+ auto prediction = mTokenManager->getPredictionsForToken(
+ event.vsync.vsyncData.frameTimelines[i].vsyncId);
EXPECT_TRUE(prediction.has_value());
- EXPECT_EQ(prediction.value().endTime, event.vsync.frameTimelines[i].deadlineTimestamp)
+ EXPECT_EQ(prediction.value().endTime,
+ event.vsync.vsyncData.frameTimelines[i].deadlineTimestamp)
<< "Deadline timestamp does not match cached value";
EXPECT_EQ(prediction.value().presentTime,
- event.vsync.frameTimelines[i].expectedVSyncTimestamp)
- << "Expected vsync timestamp does not match cached value";
+ event.vsync.vsyncData.frameTimelines[i].expectedPresentationTime)
+ << "Expected vsync.vsyncData timestamp does not match cached value";
if (i > 0) {
- EXPECT_GT(event.vsync.frameTimelines[i].deadlineTimestamp,
- event.vsync.frameTimelines[i - 1].deadlineTimestamp)
+ EXPECT_GT(event.vsync.vsyncData.frameTimelines[i].deadlineTimestamp,
+ event.vsync.vsyncData.frameTimelines[i - 1].deadlineTimestamp)
<< "Deadline timestamp out of order for frame timeline " << i;
- EXPECT_GT(event.vsync.frameTimelines[i].expectedVSyncTimestamp,
- event.vsync.frameTimelines[i - 1].expectedVSyncTimestamp)
- << "Expected vsync timestamp out of order for frame timeline " << i;
+ EXPECT_GT(event.vsync.vsyncData.frameTimelines[i].expectedPresentationTime,
+ event.vsync.vsyncData.frameTimelines[i - 1].expectedPresentationTime)
+ << "Expected vsync.vsyncData timestamp out of order for frame timeline " << i;
}
- if (event.vsync.frameTimelines[i].deadlineTimestamp == preferredDeadline) {
- EXPECT_EQ(i, event.vsync.preferredFrameTimelineIndex)
- << "Preferred frame timeline index should be " << i;
- // For the platform-preferred frame timeline, the vsync ID is 0 because the first frame
- // timeline is made before the rest.
- EXPECT_EQ(0, event.vsync.frameTimelines[i].vsyncId)
- << "Vsync ID incorrect for frame timeline " << i;
- } else {
- // Vsync ID 0 is used for the preferred frame timeline.
- EXPECT_EQ(i + 1, event.vsync.frameTimelines[i].vsyncId)
- << "Vsync ID incorrect for frame timeline " << i;
+
+ // Vsync ID order lines up with registration into test token manager.
+ EXPECT_EQ(i, event.vsync.vsyncData.frameTimelines[i].vsyncId)
+ << "Vsync ID incorrect for frame timeline " << i;
+ if (i == event.vsync.vsyncData.preferredFrameTimelineIndex) {
+ EXPECT_EQ(event.vsync.vsyncData.frameTimelines[i].deadlineTimestamp,
+ preferredVsyncData.deadlineTimestamp)
+ << "Preferred deadline timestamp incorrect" << i;
+ EXPECT_EQ(event.vsync.vsyncData.frameTimelines[i].expectedPresentationTime,
+ preferredVsyncData.expectedPresentationTime)
+ << "Preferred expected vsync.vsyncData timestamp incorrect" << i;
}
}
}
@@ -333,6 +335,8 @@
namespace {
+using namespace testing;
+
/* ------------------------------------------------------------------------
* Test cases
*/
@@ -369,7 +373,7 @@
// Use the received callback to signal a first vsync event.
// The interceptor should receive the event, as well as the connection.
- mCallback->onVSyncEvent(123, 456, 789);
+ mCallback->onVSyncEvent(123, {456, 789});
expectInterceptCallReceived(123);
expectThrottleVsyncReceived(456, mConnectionUid);
expectVsyncEventReceivedByConnection(123, 1u);
@@ -377,7 +381,7 @@
// Use the received callback to signal a second vsync event.
// The interceptor should receive the event, but the connection should
// not as it was only interested in the first.
- mCallback->onVSyncEvent(456, 123, 0);
+ mCallback->onVSyncEvent(456, {123, 0});
expectInterceptCallReceived(456);
EXPECT_FALSE(mThrottleVsyncCallRecorder.waitForUnexpectedCall().has_value());
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
@@ -395,9 +399,56 @@
// Use the received callback to signal a vsync event.
// The interceptor should receive the event, as well as the connection.
- mCallback->onVSyncEvent(123, 456, 789);
+ VSyncSource::VSyncData vsyncData = {456, 789};
+ mCallback->onVSyncEvent(123, vsyncData);
expectInterceptCallReceived(123);
- expectVsyncEventFrameTimelinesCorrect(123, 789);
+ expectVsyncEventFrameTimelinesCorrect(123, vsyncData);
+}
+
+TEST_F(EventThreadTest, getLatestVsyncEventData) {
+ const nsecs_t now = systemTime();
+ const nsecs_t preferredDeadline = now + 10000000;
+ const nsecs_t preferredExpectedPresentationTime = now + 20000000;
+ const VSyncSource::VSyncData preferredData = {preferredExpectedPresentationTime,
+ preferredDeadline};
+ EXPECT_CALL(*mVSyncSource, getLatestVSyncData()).WillOnce(Return(preferredData));
+
+ VsyncEventData vsyncEventData = mThread->getLatestVsyncEventData(mConnection);
+ EXPECT_GT(vsyncEventData.frameTimelines[0].deadlineTimestamp, now)
+ << "Deadline timestamp should be greater than frame time";
+ for (size_t i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
+ auto prediction =
+ mTokenManager->getPredictionsForToken(vsyncEventData.frameTimelines[i].vsyncId);
+ EXPECT_TRUE(prediction.has_value());
+ EXPECT_EQ(prediction.value().endTime, vsyncEventData.frameTimelines[i].deadlineTimestamp)
+ << "Deadline timestamp does not match cached value";
+ EXPECT_EQ(prediction.value().presentTime,
+ vsyncEventData.frameTimelines[i].expectedPresentationTime)
+ << "Expected vsync timestamp does not match cached value";
+ EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentationTime,
+ vsyncEventData.frameTimelines[i].deadlineTimestamp)
+ << "Expected vsync timestamp should be greater than deadline";
+
+ if (i > 0) {
+ EXPECT_GT(vsyncEventData.frameTimelines[i].deadlineTimestamp,
+ vsyncEventData.frameTimelines[i - 1].deadlineTimestamp)
+ << "Deadline timestamp out of order for frame timeline " << i;
+ EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentationTime,
+ vsyncEventData.frameTimelines[i - 1].expectedPresentationTime)
+ << "Expected vsync timestamp out of order for frame timeline " << i;
+ }
+
+ // Vsync ID order lines up with registration into test token manager.
+ EXPECT_EQ(i, vsyncEventData.frameTimelines[i].vsyncId)
+ << "Vsync ID incorrect for frame timeline " << i;
+ if (i == vsyncEventData.preferredFrameTimelineIndex) {
+ EXPECT_EQ(vsyncEventData.frameTimelines[i].deadlineTimestamp, preferredDeadline)
+ << "Preferred deadline timestamp incorrect" << i;
+ EXPECT_EQ(vsyncEventData.frameTimelines[i].expectedPresentationTime,
+ preferredExpectedPresentationTime)
+ << "Preferred expected vsync timestamp incorrect" << i;
+ }
+ }
}
TEST_F(EventThreadTest, setVsyncRateZeroPostsNoVSyncEventsToThatConnection) {
@@ -422,7 +473,7 @@
// Send a vsync event. EventThread should then make a call to the
// interceptor, and the second connection. The first connection should not
// get the event.
- mCallback->onVSyncEvent(123, 456, 0);
+ mCallback->onVSyncEvent(123, {456, 0});
expectInterceptCallReceived(123);
EXPECT_FALSE(firstConnectionEventRecorder.waitForUnexpectedCall().has_value());
expectVsyncEventReceivedByConnection("secondConnection", secondConnectionEventRecorder, 123,
@@ -437,19 +488,19 @@
// Send a vsync event. EventThread should then make a call to the
// interceptor, and the connection.
- mCallback->onVSyncEvent(123, 456, 789);
+ mCallback->onVSyncEvent(123, {456, 789});
expectInterceptCallReceived(123);
expectThrottleVsyncReceived(456, mConnectionUid);
expectVsyncEventReceivedByConnection(123, 1u);
// A second event should go to the same places.
- mCallback->onVSyncEvent(456, 123, 0);
+ mCallback->onVSyncEvent(456, {123, 0});
expectInterceptCallReceived(456);
expectThrottleVsyncReceived(123, mConnectionUid);
expectVsyncEventReceivedByConnection(456, 2u);
// A third event should go to the same places.
- mCallback->onVSyncEvent(789, 777, 111);
+ mCallback->onVSyncEvent(789, {777, 111});
expectInterceptCallReceived(789);
expectThrottleVsyncReceived(777, mConnectionUid);
expectVsyncEventReceivedByConnection(789, 3u);
@@ -462,25 +513,25 @@
expectVSyncSetEnabledCallReceived(true);
// The first event will be seen by the interceptor, and not the connection.
- mCallback->onVSyncEvent(123, 456, 789);
+ mCallback->onVSyncEvent(123, {456, 789});
expectInterceptCallReceived(123);
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
EXPECT_FALSE(mThrottleVsyncCallRecorder.waitForUnexpectedCall().has_value());
// The second event will be seen by the interceptor and the connection.
- mCallback->onVSyncEvent(456, 123, 0);
+ mCallback->onVSyncEvent(456, {123, 0});
expectInterceptCallReceived(456);
expectVsyncEventReceivedByConnection(456, 2u);
EXPECT_FALSE(mThrottleVsyncCallRecorder.waitForUnexpectedCall().has_value());
// The third event will be seen by the interceptor, and not the connection.
- mCallback->onVSyncEvent(789, 777, 744);
+ mCallback->onVSyncEvent(789, {777, 744});
expectInterceptCallReceived(789);
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
EXPECT_FALSE(mThrottleVsyncCallRecorder.waitForUnexpectedCall().has_value());
// The fourth event will be seen by the interceptor and the connection.
- mCallback->onVSyncEvent(101112, 7847, 86);
+ mCallback->onVSyncEvent(101112, {7847, 86});
expectInterceptCallReceived(101112);
expectVsyncEventReceivedByConnection(101112, 4u);
}
@@ -495,7 +546,7 @@
mConnection = nullptr;
// The first event will be seen by the interceptor, and not the connection.
- mCallback->onVSyncEvent(123, 456, 789);
+ mCallback->onVSyncEvent(123, {456, 789});
expectInterceptCallReceived(123);
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
@@ -513,13 +564,13 @@
// The first event will be seen by the interceptor, and by the connection,
// which then returns an error.
- mCallback->onVSyncEvent(123, 456, 789);
+ mCallback->onVSyncEvent(123, {456, 789});
expectInterceptCallReceived(123);
expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
// A subsequent event will be seen by the interceptor and not by the
// connection.
- mCallback->onVSyncEvent(456, 123, 0);
+ mCallback->onVSyncEvent(456, {123, 0});
expectInterceptCallReceived(456);
EXPECT_FALSE(errorConnectionEventRecorder.waitForUnexpectedCall().has_value());
@@ -544,7 +595,7 @@
// The first event will be seen by the interceptor, and by the connection,
// which then returns an error.
- mCallback->onVSyncEvent(123, 456, 789);
+ mCallback->onVSyncEvent(123, {456, 789});
expectInterceptCallReceived(123);
expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
expectVsyncEventReceivedByConnection("successConnection", secondConnectionEventRecorder, 123,
@@ -562,13 +613,13 @@
// The first event will be seen by the interceptor, and by the connection,
// which then returns an non-fatal error.
- mCallback->onVSyncEvent(123, 456, 789);
+ mCallback->onVSyncEvent(123, {456, 789});
expectInterceptCallReceived(123);
expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
// A subsequent event will be seen by the interceptor, and by the connection,
// which still then returns an non-fatal error.
- mCallback->onVSyncEvent(456, 123, 0);
+ mCallback->onVSyncEvent(456, {123, 0});
expectInterceptCallReceived(456);
expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 456, 2u);
@@ -692,7 +743,7 @@
// Use the received callback to signal a first vsync event.
// The interceptor should receive the event, but not the connection.
- mCallback->onVSyncEvent(123, 456, 789);
+ mCallback->onVSyncEvent(123, {456, 789});
expectInterceptCallReceived(123);
expectThrottleVsyncReceived(456, mThrottledConnectionUid);
mThrottledConnectionEventCallRecorder.waitForUnexpectedCall();
@@ -700,7 +751,7 @@
// Use the received callback to signal a second vsync event.
// The interceptor should receive the event, but the connection should
// not as it was only interested in the first.
- mCallback->onVSyncEvent(456, 123, 0);
+ mCallback->onVSyncEvent(456, {123, 0});
expectInterceptCallReceived(456);
expectThrottleVsyncReceived(123, mThrottledConnectionUid);
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
diff --git a/services/surfaceflinger/tests/unittests/FrameRateOverrideMappingsTest.cpp b/services/surfaceflinger/tests/unittests/FrameRateOverrideMappingsTest.cpp
new file mode 100644
index 0000000..a581c7a
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/FrameRateOverrideMappingsTest.cpp
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "FrameRateOverrideMappingsTest"
+
+#include <gtest/gtest.h>
+#include <unordered_map>
+
+#include "Scheduler/FrameRateOverrideMappings.h"
+
+namespace android::scheduler {
+
+using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride;
+using UidToFrameRateOverride = std::map<uid_t, Fps>;
+
+class FrameRateOverrideMappingsTest : public testing::Test {
+protected:
+ FrameRateOverrideMappings mFrameRateOverrideMappings;
+ UidToFrameRateOverride mFrameRateOverrideByContent;
+};
+
+namespace {
+TEST_F(FrameRateOverrideMappingsTest, testUpdateFrameRateOverridesByContent) {
+ mFrameRateOverrideByContent.clear();
+ mFrameRateOverrideByContent.emplace(0, 30.0_Hz);
+ mFrameRateOverrideByContent.emplace(1, 60.0_Hz);
+ ASSERT_TRUE(mFrameRateOverrideMappings.updateFrameRateOverridesByContent(
+ mFrameRateOverrideByContent));
+
+ ASSERT_TRUE(isApproxEqual(30.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 0, /*supportsFrameRateOverrideByContent*/ true)));
+ ASSERT_TRUE(isApproxEqual(60.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 1, /*supportsFrameRateOverrideByContent*/ true)));
+ ASSERT_EQ(std::nullopt,
+ mFrameRateOverrideMappings
+ .getFrameRateOverrideForUid(1, /*supportsFrameRateOverrideByContent*/ false));
+ ASSERT_EQ(std::nullopt,
+ mFrameRateOverrideMappings
+ .getFrameRateOverrideForUid(3, /*supportsFrameRateOverrideByContent*/ true));
+ ASSERT_EQ(std::nullopt,
+ mFrameRateOverrideMappings
+ .getFrameRateOverrideForUid(3, /*supportsFrameRateOverrideByContent*/ false));
+}
+
+TEST_F(FrameRateOverrideMappingsTest, testSetGameModeRefreshRateForUid) {
+ mFrameRateOverrideMappings.setGameModeRefreshRateForUid({1, 30.0f});
+ mFrameRateOverrideMappings.setGameModeRefreshRateForUid({2, 90.0f});
+
+ ASSERT_TRUE(isApproxEqual(30.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 1, /*supportsFrameRateOverrideByContent*/ true)));
+ ASSERT_TRUE(isApproxEqual(90.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 2, /*supportsFrameRateOverrideByContent*/ false)));
+ ASSERT_EQ(std::nullopt,
+ mFrameRateOverrideMappings
+ .getFrameRateOverrideForUid(0, /*supportsFrameRateOverrideByContent*/ true));
+ ASSERT_EQ(std::nullopt,
+ mFrameRateOverrideMappings
+ .getFrameRateOverrideForUid(0, /*supportsFrameRateOverrideByContent*/ false));
+}
+
+TEST_F(FrameRateOverrideMappingsTest, testSetPreferredRefreshRateForUid) {
+ mFrameRateOverrideMappings.setPreferredRefreshRateForUid({0, 60.0f});
+ mFrameRateOverrideMappings.setPreferredRefreshRateForUid({2, 120.0f});
+
+ ASSERT_TRUE(isApproxEqual(60.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 0, /*supportsFrameRateOverrideByContent*/ true)));
+ ASSERT_TRUE(isApproxEqual(120.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 2, /*supportsFrameRateOverrideByContent*/ false)));
+ ASSERT_EQ(std::nullopt,
+ mFrameRateOverrideMappings
+ .getFrameRateOverrideForUid(1, /*supportsFrameRateOverrideByContent*/ true));
+ ASSERT_EQ(std::nullopt,
+ mFrameRateOverrideMappings
+ .getFrameRateOverrideForUid(1, /*supportsFrameRateOverrideByContent*/ false));
+}
+
+TEST_F(FrameRateOverrideMappingsTest, testGetFrameRateOverrideForUidMixed) {
+ mFrameRateOverrideByContent.clear();
+ mFrameRateOverrideByContent.emplace(0, 30.0_Hz);
+ mFrameRateOverrideByContent.emplace(1, 60.0_Hz);
+ mFrameRateOverrideByContent.emplace(2, 45.0_Hz);
+ mFrameRateOverrideByContent.emplace(5, 120.0_Hz);
+ ASSERT_TRUE(mFrameRateOverrideMappings.updateFrameRateOverridesByContent(
+ mFrameRateOverrideByContent));
+
+ std::vector<FrameRateOverride> allFrameRateOverrides;
+ ASSERT_EQ(allFrameRateOverrides,
+ mFrameRateOverrideMappings.getAllFrameRateOverrides(
+ /*supportsFrameRateOverrideByContent*/ false));
+ allFrameRateOverrides = {{0, 30.0f}, {1, 60.0f}, {2, 45.0f}, {5, 120.0f}};
+ ASSERT_EQ(allFrameRateOverrides,
+ mFrameRateOverrideMappings.getAllFrameRateOverrides(
+ /*supportsFrameRateOverrideByContent*/ true));
+
+ mFrameRateOverrideMappings.setGameModeRefreshRateForUid({1, 30.0f});
+ mFrameRateOverrideMappings.setGameModeRefreshRateForUid({2, 90.0f});
+ mFrameRateOverrideMappings.setGameModeRefreshRateForUid({4, 120.0f});
+
+ allFrameRateOverrides.clear();
+ allFrameRateOverrides = {{1, 30.0f}, {2, 90.0f}, {4, 120.0f}};
+ ASSERT_EQ(allFrameRateOverrides,
+ mFrameRateOverrideMappings.getAllFrameRateOverrides(
+ /*supportsFrameRateOverrideByContent*/ false));
+ allFrameRateOverrides.clear();
+ allFrameRateOverrides = {{1, 30.0f}, {2, 90.0f}, {4, 120.0f}, {0, 30.0f}, {5, 120.0f}};
+ ASSERT_EQ(allFrameRateOverrides,
+ mFrameRateOverrideMappings.getAllFrameRateOverrides(
+ /*supportsFrameRateOverrideByContent*/ true));
+
+ mFrameRateOverrideMappings.setPreferredRefreshRateForUid({0, 60.0f});
+ mFrameRateOverrideMappings.setPreferredRefreshRateForUid({2, 120.0f});
+ mFrameRateOverrideMappings.setPreferredRefreshRateForUid({3, 30.0f});
+
+ allFrameRateOverrides.clear();
+ allFrameRateOverrides = {{0, 60.0f}, {2, 120.0f}, {3, 30.0f}, {1, 30.0f}, {4, 120.0f}};
+ ASSERT_EQ(allFrameRateOverrides,
+ mFrameRateOverrideMappings.getAllFrameRateOverrides(
+ /*supportsFrameRateOverrideByContent*/ false));
+ allFrameRateOverrides.clear();
+ allFrameRateOverrides = {{0, 60.0f}, {2, 120.0f}, {3, 30.0f},
+ {1, 30.0f}, {4, 120.0f}, {5, 120.0f}};
+ ASSERT_EQ(allFrameRateOverrides,
+ mFrameRateOverrideMappings.getAllFrameRateOverrides(
+ /*supportsFrameRateOverrideByContent*/ true));
+
+ ASSERT_TRUE(isApproxEqual(60.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 0, /*supportsFrameRateOverrideByContent*/ true)));
+ ASSERT_TRUE(isApproxEqual(30.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 1, /*supportsFrameRateOverrideByContent*/ true)));
+ ASSERT_TRUE(isApproxEqual(120.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 2, /*supportsFrameRateOverrideByContent*/ true)));
+ ASSERT_TRUE(isApproxEqual(30.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 3, /*supportsFrameRateOverrideByContent*/ true)));
+ ASSERT_TRUE(isApproxEqual(120.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 4, /*supportsFrameRateOverrideByContent*/ true)));
+ ASSERT_TRUE(isApproxEqual(120.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 5, /*supportsFrameRateOverrideByContent*/ true)));
+
+ ASSERT_TRUE(isApproxEqual(60.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 0, /*supportsFrameRateOverrideByContent*/ false)));
+ ASSERT_TRUE(isApproxEqual(30.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 1, /*supportsFrameRateOverrideByContent*/ false)));
+ ASSERT_TRUE(isApproxEqual(120.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 2, /*supportsFrameRateOverrideByContent*/ false)));
+ ASSERT_TRUE(isApproxEqual(30.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 3, /*supportsFrameRateOverrideByContent*/ false)));
+ ASSERT_TRUE(isApproxEqual(120.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 4, /*supportsFrameRateOverrideByContent*/ false)));
+ ASSERT_EQ(std::nullopt,
+ mFrameRateOverrideMappings
+ .getFrameRateOverrideForUid(5, /*supportsFrameRateOverrideByContent*/ false));
+}
+} // namespace
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
index 0069441..5241604 100644
--- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
@@ -48,6 +48,7 @@
namespace V2_1 = hardware::graphics::composer::V2_1;
namespace V2_4 = hardware::graphics::composer::V2_4;
+namespace aidl = aidl::android::hardware::graphics::composer3;
using Hwc2::Config;
@@ -103,7 +104,7 @@
const std::string kMetadata2Name = "com.example.metadata.2";
constexpr bool kMetadata2Mandatory = true;
- EXPECT_CALL(*mHal, getCapabilities()).WillOnce(Return(std::vector<hal::Capability>{}));
+ EXPECT_CALL(*mHal, getCapabilities()).WillOnce(Return(std::vector<aidl::Capability>{}));
EXPECT_CALL(*mHal, getLayerGenericMetadataKeys(_))
.WillOnce(DoAll(SetArgPointee<0>(std::vector<hal::LayerGenericMetadataKey>{
{kMetadata1Name, kMetadata1Mandatory},
@@ -124,7 +125,7 @@
}
TEST_F(HWComposerSetCallbackTest, handlesUnsupportedCallToGetLayerGenericMetadataKeys) {
- EXPECT_CALL(*mHal, getCapabilities()).WillOnce(Return(std::vector<hal::Capability>{}));
+ EXPECT_CALL(*mHal, getCapabilities()).WillOnce(Return(std::vector<aidl::Capability>{}));
EXPECT_CALL(*mHal, getLayerGenericMetadataKeys(_))
.WillOnce(Return(hardware::graphics::composer::V2_4::Error::UNSUPPORTED));
EXPECT_CALL(*mHal, registerCallback(_));
@@ -140,7 +141,7 @@
static constexpr hal::HWDisplayId kDisplayId = static_cast<hal::HWDisplayId>(1001);
static constexpr hal::HWLayerId kLayerId = static_cast<hal::HWLayerId>(1002);
- HWComposerLayerTest(const std::unordered_set<hal::Capability>& capabilities)
+ HWComposerLayerTest(const std::unordered_set<aidl::Capability>& capabilities)
: mCapabilies(capabilities) {
EXPECT_CALL(mDisplay, getId()).WillRepeatedly(Return(kDisplayId));
}
@@ -151,7 +152,7 @@
}
std::unique_ptr<Hwc2::mock::Composer> mHal{new StrictMock<Hwc2::mock::Composer>()};
- const std::unordered_set<hal::Capability> mCapabilies;
+ const std::unordered_set<aidl::Capability> mCapabilies;
StrictMock<HWC2::mock::Display> mDisplay;
HWC2::impl::Layer mLayer{*mHal, mCapabilies, mDisplay, kLayerId};
};
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index cdb2240..e108bea 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -97,7 +97,7 @@
void setDefaultLayerVote(Layer* layer,
LayerHistory::LayerVoteType vote) NO_THREAD_SAFETY_ANALYSIS {
auto [found, layerPair] = history().findLayer(layer->getSequence());
- if (found != LayerHistory::layerStatus::NotFound) {
+ if (found != LayerHistory::LayerStatus::NotFound) {
layerPair->second->setDefaultLayerVote(vote);
}
}
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index f48abb7..a992a91 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -228,7 +228,8 @@
mScheduler->setRefreshRateConfigs(
std::make_shared<RefreshRateConfigs>(DisplayModes{mode60, mode120}, mode60->getId()));
- sp<MockLayer> layer = sp<MockLayer>::make(mFlinger.flinger());
+ const sp<MockLayer> layer = sp<MockLayer>::make(mFlinger.flinger());
+ EXPECT_CALL(*layer, isVisible()).WillOnce(Return(true));
mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer);
@@ -240,6 +241,10 @@
EXPECT_CALL(mSchedulerCallback, changeRefreshRate(Is120Hz(), _)).Times(1);
mScheduler->chooseRefreshRateForContent();
+
+ // No-op if layer requirements have not changed.
+ EXPECT_CALL(mSchedulerCallback, changeRefreshRate(_, _)).Times(0);
+ mScheduler->chooseRefreshRateForContent();
}
} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 4fe1e98..67e47e7 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -270,6 +270,8 @@
scheduler::TestableScheduler& mutableScheduler() { return *mScheduler; }
scheduler::mock::SchedulerCallback& mockSchedulerCallback() { return mSchedulerCallback; }
+ auto& mutableVsyncModulator() { return mFlinger->mVsyncModulator; }
+
using CreateBufferQueueFunction = surfaceflinger::test::Factory::CreateBufferQueueFunction;
void setCreateBufferQueueFunction(CreateBufferQueueFunction f) {
mFactory.mCreateBufferQueue = f;
@@ -526,9 +528,11 @@
* preconditions and assert post-conditions.
*/
struct HWC2Display : public HWC2::impl::Display {
- HWC2Display(Hwc2::Composer& composer,
- const std::unordered_set<hal::Capability>& capabilities, hal::HWDisplayId id,
- hal::DisplayType type)
+ HWC2Display(
+ Hwc2::Composer& composer,
+ const std::unordered_set<aidl::android::hardware::graphics::composer3::Capability>&
+ capabilities,
+ hal::HWDisplayId id, hal::DisplayType type)
: HWC2::impl::Display(composer, capabilities, id, type) {}
~HWC2Display() {
// Prevents a call to disable vsyncs.
@@ -589,7 +593,9 @@
return *this;
}
- auto& setCapabilities(const std::unordered_set<hal::Capability>* capabilities) {
+ auto& setCapabilities(
+ const std::unordered_set<aidl::android::hardware::graphics::composer3::Capability>*
+ capabilities) {
mCapabilities = capabilities;
return *this;
}
@@ -605,7 +611,9 @@
using ::testing::Return;
using ::testing::SetArgPointee;
- static const std::unordered_set<hal::Capability> defaultCapabilities;
+ static const std::unordered_set<
+ aidl::android::hardware::graphics::composer3::Capability>
+ defaultCapabilities;
if (mCapabilities == nullptr) mCapabilities = &defaultCapabilities;
// Caution - Make sure that any values passed by reference here do
@@ -682,7 +690,8 @@
int32_t mConfigGroup = DEFAULT_CONFIG_GROUP;
hal::HWConfigId mActiveConfig = DEFAULT_ACTIVE_CONFIG;
hal::PowerMode mPowerMode = DEFAULT_POWER_MODE;
- const std::unordered_set<hal::Capability>* mCapabilities = nullptr;
+ const std::unordered_set<aidl::android::hardware::graphics::composer3::Capability>*
+ mCapabilities = nullptr;
};
class FakeDisplayDeviceInjector {
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index ed23176..eefa11f 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -72,13 +72,6 @@
EXPECT_CALL(*mVSyncTracker, currentPeriod())
.WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
- EXPECT_CALL(*mFenceUnsignaled, getStatus())
- .WillRepeatedly(Return(Fence::Status::Unsignaled));
- EXPECT_CALL(*mFenceUnsignaled2, getStatus())
- .WillRepeatedly(Return(Fence::Status::Unsignaled));
- EXPECT_CALL(*mFenceSignaled, getStatus()).WillRepeatedly(Return(Fence::Status::Signaled));
- EXPECT_CALL(*mFenceSignaled2, getStatus()).WillRepeatedly(Return(Fence::Status::Signaled));
-
mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>());
mFlinger.setupScheduler(std::unique_ptr<mock::VsyncController>(mVsyncController),
std::unique_ptr<mock::VSyncTracker>(mVSyncTracker),
@@ -89,10 +82,6 @@
mock::VsyncController* mVsyncController = new mock::VsyncController();
mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker();
- sp<mock::MockFence> mFenceUnsignaled = sp<mock::MockFence>::make();
- sp<mock::MockFence> mFenceSignaled = sp<mock::MockFence>::make();
- sp<mock::MockFence> mFenceUnsignaled2 = sp<mock::MockFence>::make();
- sp<mock::MockFence> mFenceSignaled2 = sp<mock::MockFence>::make();
struct TransactionInfo {
Vector<ComposerState> states;
@@ -129,15 +118,6 @@
transaction.frameTimelineInfo = frameTimelineInfo;
}
- void setupSingleWithComposer(TransactionInfo& transaction, uint32_t flags,
- bool syncInputWindows, int64_t desiredPresentTime,
- bool isAutoTimestamp, const FrameTimelineInfo& frameTimelineInfo,
- const Vector<ComposerState>* states) {
- setupSingle(transaction, flags, syncInputWindows, desiredPresentTime, isAutoTimestamp,
- frameTimelineInfo);
- transaction.states = *states;
- }
-
void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
@@ -263,189 +243,6 @@
EXPECT_EQ(0u, transactionQueue.size());
}
- void Flush_removesUnsignaledFromTheQueue(Vector<ComposerState> state1,
- Vector<ComposerState> state2,
- bool updateApplyToken = true) {
- ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
-
- TransactionInfo transactionA;
- setupSingleWithComposer(transactionA, ISurfaceComposer::eSynchronous,
- /*syncInputWindows*/ false,
- /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true,
- FrameTimelineInfo{}, &state1);
-
- mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states,
- transactionA.displays, transactionA.flags,
- transactionA.applyToken, transactionA.inputWindowCommands,
- transactionA.desiredPresentTime, transactionA.isAutoTimestamp,
- transactionA.uncacheBuffer, mHasListenerCallbacks, mCallbacks,
- transactionA.id);
-
- TransactionInfo transactionB;
- if (updateApplyToken) {
- transactionB.applyToken = sp<IBinder>();
- }
- setupSingleWithComposer(transactionB, ISurfaceComposer::eSynchronous,
- /*syncInputWindows*/ false,
- /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true,
- FrameTimelineInfo{}, &state2);
- mFlinger.setTransactionState(transactionB.frameTimelineInfo, transactionB.states,
- transactionB.displays, transactionB.flags,
- transactionB.applyToken, transactionB.inputWindowCommands,
- transactionB.desiredPresentTime, transactionB.isAutoTimestamp,
- transactionB.uncacheBuffer, mHasListenerCallbacks, mCallbacks,
- transactionB.id);
-
- mFlinger.flushTransactionQueues();
- EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size());
- EXPECT_EQ(0u, mFlinger.getTransactionQueue().size());
- EXPECT_EQ(2ul, mFlinger.getTransactionCommittedSignals().size());
- }
-
- void Flush_removesFromTheQueue(const Vector<ComposerState>& state) {
- ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
- EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size());
-
- TransactionInfo transaction;
- setupSingleWithComposer(transaction, ISurfaceComposer::eSynchronous,
- /*syncInputWindows*/ false,
- /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true,
- FrameTimelineInfo{}, &state);
-
- mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states,
- transaction.displays, transaction.flags,
- transaction.applyToken, transaction.inputWindowCommands,
- transaction.desiredPresentTime, transaction.isAutoTimestamp,
- transaction.uncacheBuffer, mHasListenerCallbacks, mCallbacks,
- transaction.id);
-
- mFlinger.flushTransactionQueues();
- EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size());
- EXPECT_EQ(0u, mFlinger.getTransactionQueue().size());
- EXPECT_EQ(1u, mFlinger.getTransactionCommittedSignals().size());
- }
-
- void Flush_keepsInTheQueue(const Vector<ComposerState>& state) {
- ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
- EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size());
-
- TransactionInfo transaction;
- setupSingleWithComposer(transaction, ISurfaceComposer::eSynchronous,
- /*syncInputWindows*/ false,
- /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true,
- FrameTimelineInfo{}, &state);
-
- mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states,
- transaction.displays, transaction.flags,
- transaction.applyToken, transaction.inputWindowCommands,
- transaction.desiredPresentTime, transaction.isAutoTimestamp,
- transaction.uncacheBuffer, mHasListenerCallbacks, mCallbacks,
- transaction.id);
-
- mFlinger.flushTransactionQueues();
- EXPECT_EQ(1u, mFlinger.getPendingTransactionQueue().size());
- EXPECT_EQ(0u, mFlinger.getTransactionQueue().size());
- EXPECT_EQ(0ul, mFlinger.getTransactionCommittedSignals().size());
- }
-
- void Flush_KeepsUnsignaledInTheQueue(const Vector<ComposerState>& state1,
- const Vector<ComposerState>& state2,
- bool updateApplyToken = true,
- uint32_t pendingTransactionQueueSize = 1u) {
- EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size());
- ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
- auto time = systemTime();
- TransactionInfo transactionA;
- TransactionInfo transactionB;
- setupSingleWithComposer(transactionA, ISurfaceComposer::eSynchronous,
- /*syncInputWindows*/ false,
- /*desiredPresentTime*/ time, /*isAutoTimestamp*/ true,
- FrameTimelineInfo{}, &state1);
- setupSingleWithComposer(transactionB, ISurfaceComposer::eSynchronous,
- /*syncInputWindows*/ false,
- /*desiredPresentTime*/ time, /*isAutoTimestamp*/ true,
- FrameTimelineInfo{}, &state2);
- mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states,
- transactionA.displays, transactionA.flags,
- transactionA.applyToken, transactionA.inputWindowCommands,
- transactionA.desiredPresentTime, transactionA.isAutoTimestamp,
- transactionA.uncacheBuffer, mHasListenerCallbacks, mCallbacks,
- transactionA.id);
- if (updateApplyToken) {
- transactionB.applyToken = sp<IBinder>();
- }
- mFlinger.setTransactionState(transactionB.frameTimelineInfo, transactionB.states,
- transactionB.displays, transactionB.flags,
- transactionB.applyToken, transactionB.inputWindowCommands,
- transactionB.desiredPresentTime, transactionB.isAutoTimestamp,
- transactionB.uncacheBuffer, mHasListenerCallbacks, mCallbacks,
- transactionB.id);
-
- mFlinger.flushTransactionQueues();
- EXPECT_EQ(pendingTransactionQueueSize, mFlinger.getPendingTransactionQueue().size());
- EXPECT_EQ(0u, mFlinger.getTransactionQueue().size());
- }
-
- void Flush_removesSignaledFromTheQueue(const Vector<ComposerState>& state1,
- const Vector<ComposerState>& state2) {
- ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
- EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size());
-
- auto time = systemTime();
- TransactionInfo transactionA;
- TransactionInfo transactionB;
- setupSingleWithComposer(transactionA, ISurfaceComposer::eSynchronous,
- /*syncInputWindows*/ false,
- /*desiredPresentTime*/ time, /*isAutoTimestamp*/ true,
- FrameTimelineInfo{}, &state1);
- setupSingleWithComposer(transactionB, ISurfaceComposer::eSynchronous,
- /*syncInputWindows*/ false,
- /*desiredPresentTime*/ time, /*isAutoTimestamp*/ true,
- FrameTimelineInfo{}, &state2);
- mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states,
- transactionA.displays, transactionA.flags,
- transactionA.applyToken, transactionA.inputWindowCommands,
- transactionA.desiredPresentTime, transactionA.isAutoTimestamp,
- transactionA.uncacheBuffer, mHasListenerCallbacks, mCallbacks,
- transactionA.id);
- mFlinger.setTransactionState(transactionB.frameTimelineInfo, transactionB.states,
- transactionB.displays, transactionB.flags,
- transactionB.applyToken, transactionB.inputWindowCommands,
- transactionB.desiredPresentTime, transactionB.isAutoTimestamp,
- transactionB.uncacheBuffer, mHasListenerCallbacks, mCallbacks,
- transactionB.id);
-
- mFlinger.flushTransactionQueues();
- EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size());
- EXPECT_EQ(0u, mFlinger.getTransactionQueue().size());
- EXPECT_EQ(2ul, mFlinger.getTransactionCommittedSignals().size());
- }
-
- static Vector<ComposerState> createComposerStateVector(const ComposerState& state1,
- const ComposerState& state2) {
- Vector<ComposerState> states;
- states.push_back(state1);
- states.push_back(state2);
- return states;
- }
-
- static Vector<ComposerState> createComposerStateVector(const ComposerState& state) {
- Vector<ComposerState> states;
- states.push_back(state);
- return states;
- }
-
- static ComposerState createComposerState(int layerId, sp<Fence> fence,
- uint32_t stateFlags = layer_state_t::eBufferChanged) {
- ComposerState composer_state;
- composer_state.state.bufferData = std::make_shared<BufferData>();
- composer_state.state.bufferData->acquireFence = std::move(fence);
- composer_state.state.layerId = layerId;
- composer_state.state.bufferData->flags = BufferData::BufferDataChange::fenceChanged;
- composer_state.state.flags = stateFlags;
- return composer_state;
- }
-
bool mHasListenerCallbacks = false;
std::vector<ListenerCallbacks> mCallbacks;
int mTransactionNumber = 0;
@@ -529,215 +326,721 @@
EXPECT_EQ(nullptr, ret.promote().get());
}
-TEST_F(TransactionApplicationTest, Flush_RemovesSingleSignaledFromTheQueue_LatchUnsignaled_Auto) {
- SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto;
- Flush_removesFromTheQueue(
- createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceSignaled)));
+class LatchUnsignaledTest : public TransactionApplicationTest {
+public:
+ void TearDown() override {
+ // Clear all transaction queues to release all transactions we sent
+ // in the tests. Otherwise, gmock complains about memory leaks.
+ mFlinger.getTransactionQueue().clear();
+ mFlinger.getPendingTransactionQueue().clear();
+ mFlinger.getTransactionCommittedSignals().clear();
+ mFlinger.commitTransactionsLocked(eTransactionMask);
+ mFlinger.mutableCurrentState().layersSortedByZ.clear();
+ mFlinger.mutableDrawingState().layersSortedByZ.clear();
+ }
+
+ static sp<Fence> fence(Fence::Status status) {
+ const auto fence = sp<mock::MockFence>::make();
+ EXPECT_CALL(*fence, getStatus()).WillRepeatedly(Return(status));
+ return fence;
+ }
+
+ ComposerState createComposerState(int layerId, sp<Fence> fence, uint64_t what) {
+ ComposerState state;
+ state.state.bufferData = std::make_shared<BufferData>();
+ state.state.bufferData->acquireFence = std::move(fence);
+ state.state.layerId = layerId;
+ state.state.surface =
+ sp<BufferStateLayer>::make(
+ LayerCreationArgs(mFlinger.flinger(), nullptr, "TestLayer", 0, {}))
+ ->getHandle();
+ state.state.bufferData->flags = BufferData::BufferDataChange::fenceChanged;
+
+ state.state.what = what;
+ if (what & layer_state_t::eCropChanged) {
+ state.state.crop = Rect(1, 2, 3, 4);
+ }
+ return state;
+ }
+
+ TransactionInfo createTransactionInfo(const sp<IBinder>& applyToken,
+ const std::vector<ComposerState>& states) {
+ TransactionInfo transaction;
+ const uint32_t kFlags = ISurfaceComposer::eSynchronous;
+ const bool kSyncInputWindows = false;
+ const nsecs_t kDesiredPresentTime = systemTime();
+ const bool kIsAutoTimestamp = true;
+ const auto kFrameTimelineInfo = FrameTimelineInfo{};
+
+ setupSingle(transaction, kFlags, kSyncInputWindows, kDesiredPresentTime, kIsAutoTimestamp,
+ kFrameTimelineInfo);
+ transaction.applyToken = applyToken;
+ for (const auto& state : states) {
+ transaction.states.push_back(state);
+ }
+
+ return transaction;
+ }
+
+ void setTransactionStates(const std::vector<TransactionInfo>& transactions,
+ size_t expectedTransactionsApplied,
+ size_t expectedTransactionsPending) {
+ EXPECT_EQ(0u, mFlinger.getTransactionQueue().size());
+ EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size());
+
+ for (const auto& transaction : transactions) {
+ mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states,
+ transaction.displays, transaction.flags,
+ transaction.applyToken, transaction.inputWindowCommands,
+ transaction.desiredPresentTime,
+ transaction.isAutoTimestamp, transaction.uncacheBuffer,
+ mHasListenerCallbacks, mCallbacks, transaction.id);
+ }
+ mFlinger.flushTransactionQueues();
+ EXPECT_EQ(0u, mFlinger.getTransactionQueue().size());
+ EXPECT_EQ(expectedTransactionsPending, mFlinger.getPendingTransactionQueue().size());
+ EXPECT_EQ(expectedTransactionsApplied, mFlinger.getTransactionCommittedSignals().size());
+ }
+};
+
+class LatchUnsignaledAutoSingleLayerTest : public LatchUnsignaledTest {
+public:
+ void SetUp() override {
+ LatchUnsignaledTest::SetUp();
+ SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::AutoSingleLayer;
+ }
+};
+
+TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_RemovesSingleSignaledFromTheQueue) {
+ const sp<IBinder> kApplyToken =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const auto kLayerId = 1;
+ const auto kExpectedTransactionsApplied = 1u;
+ const auto kExpectedTransactionsPending = 0u;
+
+ const auto signaledTransaction =
+ createTransactionInfo(kApplyToken,
+ {createComposerState(kLayerId, fence(Fence::Status::Signaled),
+ layer_state_t::eBufferChanged)});
+ setTransactionStates({signaledTransaction}, kExpectedTransactionsApplied,
+ kExpectedTransactionsPending);
}
-TEST_F(TransactionApplicationTest, Flush_RemovesSingleUnSignaledFromTheQueue_LatchUnsignaled_Auto) {
- SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto;
- Flush_removesFromTheQueue(
- createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled)));
+TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_RemovesSingleUnSignaledFromTheQueue) {
+ const sp<IBinder> kApplyToken =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const auto kLayerId = 1;
+ const auto kExpectedTransactionsApplied = 1u;
+ const auto kExpectedTransactionsPending = 0u;
+
+ const auto unsignaledTransaction =
+ createTransactionInfo(kApplyToken,
+ {
+ createComposerState(kLayerId,
+ fence(Fence::Status::Unsignaled),
+ layer_state_t::eBufferChanged),
+ });
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
+ kExpectedTransactionsPending);
}
-TEST_F(TransactionApplicationTest,
- Flush_KeepsUnSignaledInTheQueue_NonBufferCropChange_LatchUnsignaled_Auto) {
- SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto;
- Flush_keepsInTheQueue(createComposerStateVector(
- createComposerState(/*layerId*/ 1, mFenceUnsignaled, layer_state_t::eCropChanged)));
+TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsUnSignaledInTheQueue_NonBufferCropChange) {
+ const sp<IBinder> kApplyToken =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const auto kLayerId = 1;
+ const auto kExpectedTransactionsApplied = 0u;
+ const auto kExpectedTransactionsPending = 1u;
+
+ const auto unsignaledTransaction =
+ createTransactionInfo(kApplyToken,
+ {
+ createComposerState(kLayerId,
+ fence(Fence::Status::Unsignaled),
+ layer_state_t::eCropChanged),
+ });
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
+ kExpectedTransactionsPending);
}
-TEST_F(TransactionApplicationTest,
- Flush_KeepsUnSignaledInTheQueue_NonBufferChangeClubed_LatchUnsignaled_Auto) {
- SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto;
- Flush_keepsInTheQueue(createComposerStateVector(
- createComposerState(/*layerId*/ 1, mFenceUnsignaled,
- layer_state_t::eCropChanged | layer_state_t::eBufferChanged)));
+TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsUnSignaledInTheQueue_NonBufferChangeClubed) {
+ const sp<IBinder> kApplyToken =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const auto kLayerId = 1;
+ const auto kExpectedTransactionsApplied = 0u;
+ const auto kExpectedTransactionsPending = 1u;
+
+ const auto unsignaledTransaction =
+ createTransactionInfo(kApplyToken,
+ {
+ createComposerState(kLayerId,
+ fence(Fence::Status::Unsignaled),
+ layer_state_t::eCropChanged |
+ layer_state_t::
+ eBufferChanged),
+ });
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
+ kExpectedTransactionsPending);
}
-TEST_F(TransactionApplicationTest,
- Flush_KeepsInTheQueueSameApplyTokenMultiState_LatchUnsignaled_Auto) {
- SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto;
- Flush_keepsInTheQueue(
- createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled),
- createComposerState(/*layerId*/ 1, mFenceSignaled)));
+TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsInTheQueueSameApplyTokenMultiState) {
+ const sp<IBinder> kApplyToken =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const auto kLayerId = 1;
+ const auto kExpectedTransactionsApplied = 0u;
+ const auto kExpectedTransactionsPending = 1u;
+
+ const auto mixedTransaction =
+ createTransactionInfo(kApplyToken,
+ {
+ createComposerState(kLayerId,
+ fence(Fence::Status::Unsignaled),
+ layer_state_t::eBufferChanged),
+ createComposerState(kLayerId,
+ fence(Fence::Status::Signaled),
+ layer_state_t::eBufferChanged),
+ });
+ setTransactionStates({mixedTransaction}, kExpectedTransactionsApplied,
+ kExpectedTransactionsPending);
}
-TEST_F(TransactionApplicationTest, Flush_KeepsInTheQueue_MultipleStateTransaction_Auto) {
- SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto;
- Flush_keepsInTheQueue(
- createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled),
- createComposerState(/*layerId*/ 2, mFenceSignaled)));
+TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsInTheQueue_MultipleStateTransaction) {
+ const sp<IBinder> kApplyToken =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const auto kLayerId1 = 1;
+ const auto kLayerId2 = 2;
+ const auto kExpectedTransactionsApplied = 0u;
+ const auto kExpectedTransactionsPending = 1u;
+
+ const auto mixedTransaction =
+ createTransactionInfo(kApplyToken,
+ {
+ createComposerState(kLayerId1,
+ fence(Fence::Status::Unsignaled),
+ layer_state_t::eBufferChanged),
+ createComposerState(kLayerId2,
+ fence(Fence::Status::Signaled),
+ layer_state_t::eBufferChanged),
+ });
+ setTransactionStates({mixedTransaction}, kExpectedTransactionsApplied,
+ kExpectedTransactionsPending);
}
-TEST_F(TransactionApplicationTest, Flush_RemovesSignaledFromTheQueue_LatchUnsignaled_Auto) {
- SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto;
- Flush_removesSignaledFromTheQueue(createComposerStateVector(
- createComposerState(/*layerId*/ 1, mFenceSignaled)),
- createComposerStateVector(
- createComposerState(/*layerId*/ 2, mFenceSignaled2)));
+TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_RemovesSignaledFromTheQueue) {
+ const sp<IBinder> kApplyToken =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const auto kLayerId1 = 1;
+ const auto kLayerId2 = 2;
+ const auto kExpectedTransactionsApplied = 2u;
+ const auto kExpectedTransactionsPending = 0u;
+
+ const auto signaledTransaction =
+ createTransactionInfo(kApplyToken,
+ {
+ createComposerState(kLayerId1,
+ fence(Fence::Status::Signaled),
+ layer_state_t::eBufferChanged),
+ });
+ const auto signaledTransaction2 =
+ createTransactionInfo(kApplyToken,
+ {
+ createComposerState(kLayerId2,
+ fence(Fence::Status::Signaled),
+ layer_state_t::eBufferChanged),
+ });
+ setTransactionStates({signaledTransaction, signaledTransaction2}, kExpectedTransactionsApplied,
+ kExpectedTransactionsPending);
}
-TEST_F(TransactionApplicationTest, Flush_RemoveSignaledWithUnsignaledIntact_LatchUnsignaled_Auto) {
- SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto;
- Flush_KeepsUnsignaledInTheQueue(createComposerStateVector(
- createComposerState(/*layerId*/ 1, mFenceSignaled)),
- createComposerStateVector(
- createComposerState(/*layerId*/ 2, mFenceUnsignaled)));
- EXPECT_EQ(1ul, mFlinger.getTransactionCommittedSignals().size());
+TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_RemoveSignaledWithUnsignaledIntact) {
+ const sp<IBinder> kApplyToken1 =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const sp<IBinder> kApplyToken2 = sp<BBinder>::make();
+ const auto kLayerId1 = 1;
+ const auto kLayerId2 = 2;
+ const auto kExpectedTransactionsApplied = 1u;
+ const auto kExpectedTransactionsPending = 1u;
+
+ const auto signaledTransaction =
+ createTransactionInfo(kApplyToken1,
+ {
+ createComposerState(kLayerId1,
+ fence(Fence::Status::Signaled),
+ layer_state_t::eBufferChanged),
+ });
+ const auto unsignaledTransaction =
+ createTransactionInfo(kApplyToken2,
+ {
+ createComposerState(kLayerId2,
+ fence(Fence::Status::Unsignaled),
+ layer_state_t::eBufferChanged),
+ });
+ setTransactionStates({signaledTransaction, unsignaledTransaction}, kExpectedTransactionsApplied,
+ kExpectedTransactionsPending);
}
-TEST_F(TransactionApplicationTest,
- Flush_KeepsTransactionInTheQueueSameApplyToken_LatchUnsignaled_Auto) {
- SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto;
- Flush_KeepsUnsignaledInTheQueue(createComposerStateVector(
- createComposerState(/*layerId*/ 1, mFenceUnsignaled)),
- createComposerStateVector(
- createComposerState(/*layerId*/ 2, mFenceSignaled)),
- /*updateApplyToken*/ false);
- EXPECT_EQ(1ul, mFlinger.getTransactionCommittedSignals().size());
+TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsTransactionInTheQueueSameApplyToken) {
+ const sp<IBinder> kApplyToken =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const auto kLayerId1 = 1;
+ const auto kLayerId2 = 2;
+ const auto kExpectedTransactionsApplied = 1u;
+ const auto kExpectedTransactionsPending = 1u;
+
+ const auto unsignaledTransaction =
+ createTransactionInfo(kApplyToken,
+ {
+ createComposerState(kLayerId1,
+ fence(Fence::Status::Unsignaled),
+ layer_state_t::eBufferChanged),
+ });
+ const auto signaledTransaction =
+ createTransactionInfo(kApplyToken,
+ {
+ createComposerState(kLayerId2,
+ fence(Fence::Status::Signaled),
+ layer_state_t::eBufferChanged),
+ });
+ setTransactionStates({unsignaledTransaction, signaledTransaction}, kExpectedTransactionsApplied,
+ kExpectedTransactionsPending);
}
-TEST_F(TransactionApplicationTest, Flush_KeepsTransactionInTheQueue_LatchUnsignaled_Auto) {
- SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto;
- Flush_KeepsUnsignaledInTheQueue(createComposerStateVector(
- createComposerState(/*layerId*/ 1, mFenceUnsignaled)),
- createComposerStateVector(
- createComposerState(/*layerId*/ 2, mFenceUnsignaled)),
- /*updateApplyToken*/ true,
- /*pendingTransactionQueueSize*/ 2u);
- EXPECT_EQ(0ul, mFlinger.getTransactionCommittedSignals().size());
+TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsTransactionInTheQueue) {
+ const sp<IBinder> kApplyToken1 =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const sp<IBinder> kApplyToken2 = sp<BBinder>::make();
+ const auto kLayerId1 = 1;
+ const auto kLayerId2 = 2;
+ const auto kExpectedTransactionsApplied = 1u;
+ const auto kExpectedTransactionsPending = 1u;
+
+ const auto unsignaledTransaction =
+ createTransactionInfo(kApplyToken1,
+ {
+ createComposerState(kLayerId1,
+ fence(Fence::Status::Unsignaled),
+ layer_state_t::eBufferChanged),
+ });
+ const auto unsignaledTransaction2 =
+ createTransactionInfo(kApplyToken2,
+ {
+ createComposerState(kLayerId2,
+ fence(Fence::Status::Unsignaled),
+ layer_state_t::eBufferChanged),
+ });
+ setTransactionStates({unsignaledTransaction, unsignaledTransaction2},
+ kExpectedTransactionsApplied, kExpectedTransactionsPending);
}
-TEST_F(TransactionApplicationTest, Flush_RemovesSignaledFromTheQueue_LatchUnsignaled_Disabled) {
- SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled;
- Flush_removesFromTheQueue(
- createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceSignaled)));
+TEST_F(LatchUnsignaledAutoSingleLayerTest, DontLatchUnsignaledWhenEarlyOffset) {
+ const sp<IBinder> kApplyToken =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const auto kLayerId = 1;
+ const auto kExpectedTransactionsApplied = 0u;
+ const auto kExpectedTransactionsPending = 1u;
+
+ const auto unsignaledTransaction =
+ createTransactionInfo(kApplyToken,
+ {
+ createComposerState(kLayerId,
+ fence(Fence::Status::Unsignaled),
+ layer_state_t::eBufferChanged),
+ });
+
+ // Get VsyncModulator out of the default config
+ static_cast<void>(mFlinger.mutableVsyncModulator()->onRefreshRateChangeInitiated());
+
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
+ kExpectedTransactionsPending);
}
-TEST_F(TransactionApplicationTest, Flush_KeepsInTheQueue_LatchUnsignaled_Disabled) {
- SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled;
- Flush_keepsInTheQueue(
- createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled)));
+class LatchUnsignaledDisabledTest : public LatchUnsignaledTest {
+public:
+ void SetUp() override {
+ LatchUnsignaledTest::SetUp();
+ SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled;
+ }
+};
+
+TEST_F(LatchUnsignaledDisabledTest, Flush_RemovesSignaledFromTheQueue) {
+ const sp<IBinder> kApplyToken =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const auto kLayerId = 1;
+ const auto kExpectedTransactionsApplied = 1u;
+ const auto kExpectedTransactionsPending = 0u;
+
+ const auto signaledTransaction =
+ createTransactionInfo(kApplyToken,
+ {createComposerState(kLayerId, fence(Fence::Status::Signaled),
+ layer_state_t::eBufferChanged)});
+ setTransactionStates({signaledTransaction}, kExpectedTransactionsApplied,
+ kExpectedTransactionsPending);
}
-TEST_F(TransactionApplicationTest, Flush_KeepsInTheQueueSameLayerId_LatchUnsignaled_Disabled) {
- SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled;
- Flush_keepsInTheQueue(
- createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled),
- createComposerState(/*layerId*/ 1, mFenceUnsignaled)));
+TEST_F(LatchUnsignaledDisabledTest, Flush_KeepsInTheQueue) {
+ const sp<IBinder> kApplyToken =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const auto kLayerId = 1;
+ const auto kExpectedTransactionsApplied = 0u;
+ const auto kExpectedTransactionsPending = 1u;
+
+ const auto unsignaledTransaction =
+ createTransactionInfo(kApplyToken,
+ {
+ createComposerState(kLayerId,
+ fence(Fence::Status::Unsignaled),
+ layer_state_t::eBufferChanged),
+ });
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
+ kExpectedTransactionsPending);
}
-TEST_F(TransactionApplicationTest, Flush_KeepsInTheQueueDifferentLayerId_LatchUnsignaled_Disabled) {
- SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled;
- Flush_keepsInTheQueue(
- createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled),
- createComposerState(/*layerId*/ 2, mFenceUnsignaled)));
+TEST_F(LatchUnsignaledDisabledTest, Flush_KeepsInTheQueueSameLayerId) {
+ const sp<IBinder> kApplyToken =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const auto kLayerId = 1;
+ const auto kExpectedTransactionsApplied = 0u;
+ const auto kExpectedTransactionsPending = 1u;
+
+ const auto unsignaledTransaction =
+ createTransactionInfo(kApplyToken,
+ {
+ createComposerState(kLayerId,
+ fence(Fence::Status::Unsignaled),
+ layer_state_t::eBufferChanged),
+ createComposerState(kLayerId,
+ fence(Fence::Status::Unsignaled),
+ layer_state_t::eBufferChanged),
+ });
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
+ kExpectedTransactionsPending);
}
-TEST_F(TransactionApplicationTest, Flush_RemovesSignaledFromTheQueue_LatchUnSignaled_Disabled) {
- SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled;
- Flush_removesSignaledFromTheQueue(createComposerStateVector(
- createComposerState(/*layerId*/ 1, mFenceSignaled)),
- createComposerStateVector(
- createComposerState(/*layerId*/ 2, mFenceSignaled2)));
+TEST_F(LatchUnsignaledDisabledTest, Flush_KeepsInTheQueueDifferentLayerId) {
+ const sp<IBinder> kApplyToken =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const auto kLayerId1 = 1;
+ const auto kLayerId2 = 2;
+ const auto kExpectedTransactionsApplied = 0u;
+ const auto kExpectedTransactionsPending = 1u;
+
+ const auto unsignaledTransaction =
+ createTransactionInfo(kApplyToken,
+ {
+ createComposerState(kLayerId1,
+ fence(Fence::Status::Unsignaled),
+ layer_state_t::eBufferChanged),
+ createComposerState(kLayerId2,
+ fence(Fence::Status::Unsignaled),
+ layer_state_t::eBufferChanged),
+ });
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
+ kExpectedTransactionsPending);
}
-TEST_F(TransactionApplicationTest,
- Flush_KeepInTheQueueDifferentApplyToken_LatchUnsignaled_Disabled) {
- SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled;
- Flush_KeepsUnsignaledInTheQueue(createComposerStateVector(
- createComposerState(/*layerId*/ 1, mFenceUnsignaled)),
- createComposerStateVector(
- createComposerState(/*layerId*/ 2, mFenceSignaled)));
- EXPECT_EQ(1ul, mFlinger.getTransactionCommittedSignals().size());
+TEST_F(LatchUnsignaledDisabledTest, Flush_RemovesSignaledFromTheQueue_MultipleLayers) {
+ const sp<IBinder> kApplyToken =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const auto kLayerId1 = 1;
+ const auto kLayerId2 = 2;
+ const auto kExpectedTransactionsApplied = 2u;
+ const auto kExpectedTransactionsPending = 0u;
+
+ const auto signaledTransaction =
+ createTransactionInfo(kApplyToken,
+ {
+ createComposerState(kLayerId1,
+ fence(Fence::Status::Signaled),
+ layer_state_t::eBufferChanged),
+ });
+ const auto signaledTransaction2 =
+ createTransactionInfo(kApplyToken,
+ {
+ createComposerState(kLayerId2,
+ fence(Fence::Status::Signaled),
+ layer_state_t::eBufferChanged),
+ });
+ setTransactionStates({signaledTransaction, signaledTransaction2}, kExpectedTransactionsApplied,
+ kExpectedTransactionsPending);
}
-TEST_F(TransactionApplicationTest, Flush_KeepInTheQueueSameApplyToken_LatchUnsignaled_Disabled) {
- SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled;
- Flush_KeepsUnsignaledInTheQueue(createComposerStateVector(
- createComposerState(/*layerId*/ 1, mFenceSignaled)),
- createComposerStateVector(
- createComposerState(/*layerId*/ 2, mFenceUnsignaled)),
- /*updateApplyToken*/ false);
- EXPECT_EQ(1ul, mFlinger.getTransactionCommittedSignals().size());
+TEST_F(LatchUnsignaledDisabledTest, Flush_KeepInTheQueueDifferentApplyToken) {
+ const sp<IBinder> kApplyToken1 =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const sp<IBinder> kApplyToken2 = sp<BBinder>::make();
+ const auto kLayerId1 = 1;
+ const auto kLayerId2 = 2;
+ const auto kExpectedTransactionsApplied = 1u;
+ const auto kExpectedTransactionsPending = 1u;
+
+ const auto unsignaledTransaction =
+ createTransactionInfo(kApplyToken1,
+ {
+ createComposerState(kLayerId1,
+ fence(Fence::Status::Unsignaled),
+ layer_state_t::eBufferChanged),
+ });
+ const auto signaledTransaction =
+ createTransactionInfo(kApplyToken2,
+ {
+ createComposerState(kLayerId2,
+ fence(Fence::Status::Signaled),
+ layer_state_t::eBufferChanged),
+ });
+ setTransactionStates({unsignaledTransaction, signaledTransaction}, kExpectedTransactionsApplied,
+ kExpectedTransactionsPending);
}
-TEST_F(TransactionApplicationTest, Flush_KeepInTheUnsignaledTheQueue_LatchUnsignaled_Disabled) {
- SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled;
- Flush_KeepsUnsignaledInTheQueue(createComposerStateVector(
- createComposerState(/*layerId*/ 1, mFenceUnsignaled)),
- createComposerStateVector(
- createComposerState(/*layerId*/ 2, mFenceUnsignaled)),
- /*updateApplyToken*/ false);
- EXPECT_EQ(0ul, mFlinger.getTransactionCommittedSignals().size());
+TEST_F(LatchUnsignaledDisabledTest, Flush_KeepInTheQueueSameApplyToken) {
+ const sp<IBinder> kApplyToken =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const auto kLayerId1 = 1;
+ const auto kLayerId2 = 2;
+ const auto kExpectedTransactionsApplied = 1u;
+ const auto kExpectedTransactionsPending = 1u;
+
+ const auto signaledTransaction =
+ createTransactionInfo(kApplyToken,
+ {
+ createComposerState(kLayerId1,
+ fence(Fence::Status::Signaled),
+ layer_state_t::eBufferChanged),
+ });
+ const auto unsignaledTransaction =
+ createTransactionInfo(kApplyToken,
+ {
+ createComposerState(kLayerId2,
+ fence(Fence::Status::Unsignaled),
+ layer_state_t::eBufferChanged),
+ });
+ setTransactionStates({signaledTransaction, unsignaledTransaction}, kExpectedTransactionsApplied,
+ kExpectedTransactionsPending);
}
-TEST_F(TransactionApplicationTest, Flush_RemovesSignaledFromTheQueue_LatchUnsignaled_Always) {
- SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always;
- Flush_removesFromTheQueue(
- createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceSignaled)));
+TEST_F(LatchUnsignaledDisabledTest, Flush_KeepInTheUnsignaledTheQueue) {
+ const sp<IBinder> kApplyToken =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const auto kLayerId1 = 1;
+ const auto kLayerId2 = 2;
+ const auto kExpectedTransactionsApplied = 0u;
+ const auto kExpectedTransactionsPending = 1u;
+
+ const auto unsignaledTransaction =
+ createTransactionInfo(kApplyToken,
+ {
+ createComposerState(kLayerId1,
+ fence(Fence::Status::Unsignaled),
+ layer_state_t::eBufferChanged),
+ });
+ const auto unsignaledTransaction2 =
+ createTransactionInfo(kApplyToken,
+ {
+ createComposerState(kLayerId2,
+ fence(Fence::Status::Unsignaled),
+ layer_state_t::eBufferChanged),
+ });
+ setTransactionStates({unsignaledTransaction, unsignaledTransaction2},
+ kExpectedTransactionsApplied, kExpectedTransactionsPending);
}
-TEST_F(TransactionApplicationTest, Flush_RemovesFromTheQueue_LatchUnsignaled_Always) {
- SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always;
- Flush_removesFromTheQueue(
- createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled)));
+class LatchUnsignaledAlwaysTest : public LatchUnsignaledTest {
+public:
+ void SetUp() override {
+ LatchUnsignaledTest::SetUp();
+ SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always;
+ }
+};
+
+TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesSignaledFromTheQueue) {
+ const sp<IBinder> kApplyToken =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const auto kLayerId = 1;
+ const auto kExpectedTransactionsApplied = 1u;
+ const auto kExpectedTransactionsPending = 0u;
+
+ const auto signaledTransaction =
+ createTransactionInfo(kApplyToken,
+ {createComposerState(kLayerId, fence(Fence::Status::Signaled),
+ layer_state_t::eBufferChanged)});
+ setTransactionStates({signaledTransaction}, kExpectedTransactionsApplied,
+ kExpectedTransactionsPending);
}
-TEST_F(TransactionApplicationTest, Flush_RemovesFromTheQueueSameLayerId_LatchUnsignaled_Always) {
- SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always;
- Flush_removesFromTheQueue(
- createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled),
- createComposerState(/*layerId*/ 1, mFenceSignaled)));
+TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesFromTheQueue) {
+ const sp<IBinder> kApplyToken =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const auto kLayerId = 1;
+ const auto kExpectedTransactionsApplied = 1u;
+ const auto kExpectedTransactionsPending = 0u;
+
+ const auto unsignaledTransaction =
+ createTransactionInfo(kApplyToken,
+ {createComposerState(kLayerId, fence(Fence::Status::Unsignaled),
+ layer_state_t::eBufferChanged)});
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
+ kExpectedTransactionsPending);
}
-TEST_F(TransactionApplicationTest,
- Flush_RemovesFromTheQueueDifferentLayerId_LatchUnsignaled_Always) {
- SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always;
- Flush_removesFromTheQueue(
- createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled),
- createComposerState(/*layerId*/ 2, mFenceSignaled)));
+TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesFromTheQueueSameLayerId) {
+ const sp<IBinder> kApplyToken =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const auto kLayerId = 1;
+ const auto kExpectedTransactionsApplied = 1u;
+ const auto kExpectedTransactionsPending = 0u;
+
+ const auto mixedTransaction =
+ createTransactionInfo(kApplyToken,
+ {createComposerState(kLayerId, fence(Fence::Status::Unsignaled),
+ layer_state_t::eBufferChanged),
+ createComposerState(kLayerId, fence(Fence::Status::Signaled),
+ layer_state_t::eBufferChanged)});
+ setTransactionStates({mixedTransaction}, kExpectedTransactionsApplied,
+ kExpectedTransactionsPending);
}
-TEST_F(TransactionApplicationTest, Flush_RemovesSignaledFromTheQueue_LatchUnSignaled_Always) {
- SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always;
- Flush_removesSignaledFromTheQueue(createComposerStateVector(
- createComposerState(/*layerId*/ 1, mFenceSignaled)),
- createComposerStateVector(
- createComposerState(/*layerId*/ 2, mFenceSignaled2)));
+TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesFromTheQueueDifferentLayerId) {
+ const sp<IBinder> kApplyToken =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const auto kLayerId1 = 1;
+ const auto kLayerId2 = 2;
+ const auto kExpectedTransactionsApplied = 1u;
+ const auto kExpectedTransactionsPending = 0u;
+
+ const auto mixedTransaction =
+ createTransactionInfo(kApplyToken,
+ {createComposerState(kLayerId1, fence(Fence::Status::Unsignaled),
+ layer_state_t::eBufferChanged),
+ createComposerState(kLayerId2, fence(Fence::Status::Signaled),
+ layer_state_t::eBufferChanged)});
+ setTransactionStates({mixedTransaction}, kExpectedTransactionsApplied,
+ kExpectedTransactionsPending);
}
-TEST_F(TransactionApplicationTest,
- Flush_RemovesFromTheQueueDifferentApplyToken_LatchUnsignaled_Always) {
- SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always;
- Flush_removesUnsignaledFromTheQueue(createComposerStateVector(
- createComposerState(/*layerId*/ 1, mFenceSignaled)),
- createComposerStateVector(
- createComposerState(/*layerId*/ 2,
- mFenceUnsignaled)));
+TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesSignaledFromTheQueue_MultipleLayers) {
+ const sp<IBinder> kApplyToken =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const auto kLayerId1 = 1;
+ const auto kLayerId2 = 2;
+ const auto kExpectedTransactionsApplied = 2u;
+ const auto kExpectedTransactionsPending = 0u;
+
+ const auto signaledTransaction =
+ createTransactionInfo(kApplyToken,
+ {
+ createComposerState(kLayerId1,
+ fence(Fence::Status::Signaled),
+ layer_state_t::eBufferChanged),
+ });
+ const auto signaledTransaction2 =
+ createTransactionInfo(kApplyToken,
+ {
+ createComposerState(kLayerId2,
+ fence(Fence::Status::Signaled),
+ layer_state_t::eBufferChanged),
+ });
+ setTransactionStates({signaledTransaction, signaledTransaction2}, kExpectedTransactionsApplied,
+ kExpectedTransactionsPending);
}
-TEST_F(TransactionApplicationTest,
- Flush_RemovesUnsignaledFromTheQueueSameApplyToken_LatchUnsignaled_Always) {
- SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always;
- Flush_removesUnsignaledFromTheQueue(createComposerStateVector(
- createComposerState(/*layerId*/ 1,
- mFenceUnsignaled)),
- createComposerStateVector(
- createComposerState(/*layerId*/ 2, mFenceSignaled)),
- /*updateApplyToken*/ false);
+TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesFromTheQueueDifferentApplyToken) {
+ const sp<IBinder> kApplyToken1 =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const sp<IBinder> kApplyToken2 = sp<BBinder>::make();
+ const auto kLayerId1 = 1;
+ const auto kLayerId2 = 2;
+ const auto kExpectedTransactionsApplied = 2u;
+ const auto kExpectedTransactionsPending = 0u;
+
+ const auto signaledTransaction =
+ createTransactionInfo(kApplyToken1,
+ {
+ createComposerState(kLayerId1,
+ fence(Fence::Status::Signaled),
+ layer_state_t::eBufferChanged),
+ });
+ const auto unsignaledTransaction =
+ createTransactionInfo(kApplyToken2,
+ {
+ createComposerState(kLayerId2,
+ fence(Fence::Status::Unsignaled),
+ layer_state_t::eBufferChanged),
+ });
+ setTransactionStates({signaledTransaction, unsignaledTransaction}, kExpectedTransactionsApplied,
+ kExpectedTransactionsPending);
}
-TEST_F(TransactionApplicationTest, Flush_RemovesUnsignaledFromTheQueue_LatchUnsignaled_Always) {
- SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always;
- Flush_removesUnsignaledFromTheQueue(createComposerStateVector(
- createComposerState(/*layerId*/ 1,
- mFenceUnsignaled)),
- createComposerStateVector(
- createComposerState(/*layerId*/ 2,
- mFenceUnsignaled)));
+TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesUnsignaledFromTheQueueSameApplyToken) {
+ const sp<IBinder> kApplyToken =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const auto kLayerId1 = 1;
+ const auto kLayerId2 = 2;
+ const auto kExpectedTransactionsApplied = 2u;
+ const auto kExpectedTransactionsPending = 0u;
+
+ const auto unsignaledTransaction =
+ createTransactionInfo(kApplyToken,
+ {
+ createComposerState(kLayerId1,
+ fence(Fence::Status::Unsignaled),
+ layer_state_t::eBufferChanged),
+ });
+ const auto signaledTransaction =
+ createTransactionInfo(kApplyToken,
+ {
+ createComposerState(kLayerId2,
+ fence(Fence::Status::Signaled),
+ layer_state_t::eBufferChanged),
+ });
+ setTransactionStates({unsignaledTransaction, signaledTransaction}, kExpectedTransactionsApplied,
+ kExpectedTransactionsPending);
+}
+
+TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesUnsignaledFromTheQueue) {
+ const sp<IBinder> kApplyToken1 =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const sp<IBinder> kApplyToken2 = sp<BBinder>::make();
+ const auto kLayerId1 = 1;
+ const auto kLayerId2 = 2;
+ const auto kExpectedTransactionsApplied = 2u;
+ const auto kExpectedTransactionsPending = 0u;
+
+ const auto unsignaledTransaction =
+ createTransactionInfo(kApplyToken1,
+ {
+ createComposerState(kLayerId1,
+ fence(Fence::Status::Unsignaled),
+ layer_state_t::eBufferChanged),
+ });
+ const auto unsignaledTransaction2 =
+ createTransactionInfo(kApplyToken2,
+ {
+ createComposerState(kLayerId2,
+ fence(Fence::Status::Unsignaled),
+ layer_state_t::eBufferChanged),
+ });
+ setTransactionStates({unsignaledTransaction, unsignaledTransaction2},
+ kExpectedTransactionsApplied, kExpectedTransactionsPending);
+}
+
+TEST_F(LatchUnsignaledAlwaysTest, LatchUnsignaledWhenEarlyOffset) {
+ const sp<IBinder> kApplyToken =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const auto kLayerId = 1;
+ const auto kExpectedTransactionsApplied = 1u;
+ const auto kExpectedTransactionsPending = 0u;
+
+ const auto unsignaledTransaction =
+ createTransactionInfo(kApplyToken,
+ {
+ createComposerState(kLayerId,
+ fence(Fence::Status::Unsignaled),
+ layer_state_t::eBufferChanged),
+ });
+
+ // Get VsyncModulator out of the default config
+ static_cast<void>(mFlinger.mutableVsyncModulator()->onRefreshRateChangeInitiated());
+
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
+ kExpectedTransactionsPending);
}
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
index 271b1c0..ab893a3 100644
--- a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
@@ -70,23 +70,32 @@
t1.displays.add(display);
}
- TransactionProtoParser::LayerHandleToIdFn getLayerIdFn = [&](const sp<IBinder>& handle) {
- return (handle == layerHandle) ? 42 : -1;
- };
- TransactionProtoParser::DisplayHandleToIdFn getDisplayIdFn = [&](const sp<IBinder>& handle) {
- return (handle == displayHandle) ? 43 : -1;
- };
- TransactionProtoParser::LayerIdToHandleFn getLayerHandleFn = [&](int32_t id) {
- return (id == 42) ? layerHandle : nullptr;
- };
- TransactionProtoParser::DisplayIdToHandleFn getDisplayHandleFn = [&](int32_t id) {
- return (id == 43) ? displayHandle : nullptr;
+ class TestMapper : public TransactionProtoParser::FlingerDataMapper {
+ public:
+ sp<IBinder> layerHandle;
+ sp<IBinder> displayHandle;
+
+ TestMapper(sp<IBinder> layerHandle, sp<IBinder> displayHandle)
+ : layerHandle(layerHandle), displayHandle(displayHandle) {}
+
+ sp<IBinder> getLayerHandle(int32_t id) const override {
+ return (id == 42) ? layerHandle : nullptr;
+ }
+ int32_t getLayerId(const sp<IBinder>& handle) const override {
+ return (handle == layerHandle) ? 42 : -1;
+ }
+ sp<IBinder> getDisplayHandle(int32_t id) const {
+ return (id == 43) ? displayHandle : nullptr;
+ }
+ int32_t getDisplayId(const sp<IBinder>& handle) const {
+ return (handle == displayHandle) ? 43 : -1;
+ }
};
- proto::TransactionState proto =
- TransactionProtoParser::toProto(t1, getLayerIdFn, getDisplayIdFn);
- TransactionState t2 =
- TransactionProtoParser::fromProto(proto, getLayerHandleFn, getDisplayHandleFn);
+ TransactionProtoParser parser(std::make_unique<TestMapper>(layerHandle, displayHandle));
+
+ proto::TransactionState proto = parser.toProto(t1);
+ TransactionState t2 = parser.fromProto(proto);
ASSERT_EQ(t1.originPid, t2.originPid);
ASSERT_EQ(t1.originUid, t2.originUid);
diff --git a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
index 39dbb07..61b72a0 100644
--- a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
@@ -178,8 +178,8 @@
// verify we can still retrieve the layer change from the first entry containing starting
// states.
EXPECT_GT(proto.entry().size(), 0);
- EXPECT_GT(proto.entry(0).transactions().size(), 0);
- EXPECT_GT(proto.entry(0).added_layers().size(), 0);
+ EXPECT_EQ(proto.entry(0).transactions().size(), 1);
+ EXPECT_EQ(proto.entry(0).added_layers().size(), 2);
EXPECT_EQ(proto.entry(0).transactions(0).layer_changes().size(), 2);
EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).layer_id(), mParentLayerId);
EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).z(), 42);
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 0765d5b..a1aa7e8 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -43,6 +43,8 @@
using android::hardware::graphics::composer::V2_4::IComposerCallback;
using android::hardware::graphics::composer::V2_4::IComposerClient;
+using aidl::android::hardware::graphics::common::DisplayDecorationSupport;
+
class Composer : public Hwc2::Composer {
public:
using Display = android::hardware::graphics::composer::V2_1::Display;
@@ -50,7 +52,8 @@
~Composer() override;
MOCK_METHOD(bool, isSupported, (OptionalFeature), (const, override));
- MOCK_METHOD0(getCapabilities, std::vector<IComposer::Capability>());
+ MOCK_METHOD0(getCapabilities,
+ std::vector<aidl::android::hardware::graphics::composer3::Capability>());
MOCK_METHOD0(dumpDebugInfo, std::string());
MOCK_METHOD1(registerCallback, void(HWC2::ComposerCallback&));
MOCK_METHOD0(resetCommands, void());
@@ -149,9 +152,11 @@
V2_4::Error(std::vector<IComposerClient::LayerGenericMetadataKey>*));
MOCK_METHOD3(getClientTargetProperty,
Error(Display, IComposerClient::ClientTargetProperty*, float*));
- MOCK_METHOD3(setLayerWhitePointNits, Error(Display, Layer, float));
+ MOCK_METHOD3(setLayerBrightness, Error(Display, Layer, float));
MOCK_METHOD3(setLayerBlockingRegion,
Error(Display, Layer, const std::vector<IComposerClient::Rect>&));
+ MOCK_METHOD2(getDisplayDecorationSupport,
+ Error(Display, std::optional<DisplayDecorationSupport>*));
};
} // namespace Hwc2::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
index 9015944..570ffeb 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
@@ -95,6 +95,10 @@
MOCK_METHOD(hal::Error, setContentType, (hal::ContentType), (override));
MOCK_METHOD(hal::Error, getClientTargetProperty, (hal::ClientTargetProperty *, float *),
(override));
+ MOCK_METHOD(
+ hal::Error, getDisplayDecorationSupport,
+ (std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport> *),
+ (override));
};
class Layer : public HWC2::Layer {
@@ -127,7 +131,7 @@
MOCK_METHOD(hal::Error, setColorTransform, (const android::mat4 &), (override));
MOCK_METHOD(hal::Error, setLayerGenericMetadata,
(const std::string &, bool, const std::vector<uint8_t> &), (override));
- MOCK_METHOD(hal::Error, setWhitePointNits, (float whitePointNits), (override));
+ MOCK_METHOD(hal::Error, setBrightness, (float), (override));
MOCK_METHOD(hal::Error, setBlockingRegion, (const android::Region &), (override));
};
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index d25973e..c5ca86a 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -44,6 +44,8 @@
status_t(const sp<android::EventThreadConnection> &));
MOCK_METHOD2(setVsyncRate, void(uint32_t, const sp<android::EventThreadConnection> &));
MOCK_METHOD1(requestNextVsync, void(const sp<android::EventThreadConnection> &));
+ MOCK_METHOD(VsyncEventData, getLatestVsyncEventData,
+ (const sp<android::EventThreadConnection> &), (const));
MOCK_METHOD1(requestLatestConfig, void(const sp<android::EventThreadConnection> &));
MOCK_METHOD1(pauseVsyncCallback, void(bool));
MOCK_METHOD0(getEventThreadConnectionCount, size_t());