Snap for 8505378 from 8e5ba105c7d1e4606f79d5ca941be1dfe57261a6 to mainline-go-wifi-release
Change-Id: Ie1605cd6f5261b1e9572fcb502d70175a5646937
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 1c3a4f2..32ffe14 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -63,6 +63,8 @@
chmod 0666 /sys/kernel/tracing/events/cpuhp/cpuhp_pause/enable
chmod 0666 /sys/kernel/debug/tracing/events/power/gpu_frequency/enable
chmod 0666 /sys/kernel/tracing/events/power/gpu_frequency/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/power/gpu_work_period/enable
+ chmod 0666 /sys/kernel/tracing/events/power/gpu_work_period/enable
chmod 0666 /sys/kernel/debug/tracing/events/power/suspend_resume/enable
chmod 0666 /sys/kernel/tracing/events/power/suspend_resume/enable
chmod 0666 /sys/kernel/debug/tracing/events/cpufreq_interactive/enable
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 24b201f..890c15f 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -2733,8 +2733,8 @@
const android::base::unique_fd& screenshot_fd_in,
bool is_screenshot_requested) {
// Duplicate the fds because the passed in fds don't outlive the binder transaction.
- bugreport_fd.reset(dup(bugreport_fd_in.get()));
- screenshot_fd.reset(dup(screenshot_fd_in.get()));
+ bugreport_fd.reset(fcntl(bugreport_fd_in.get(), F_DUPFD_CLOEXEC, 0));
+ screenshot_fd.reset(fcntl(screenshot_fd_in.get(), F_DUPFD_CLOEXEC, 0));
SetOptionsFromMode(bugreport_mode, this, is_screenshot_requested);
}
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index c104fea..b4aa88e 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -473,7 +473,8 @@
StringPrintf("%smisc/installd/using_project_ids", android_data_dir.c_str());
sUsingProjectIdsFlag = access(using_project_ids.c_str(), F_OK) == 0;
});
- return sUsingProjectIdsFlag;
+ // return sUsingProjectIdsFlag;
+ return false;
}
static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid, gid_t gid,
@@ -632,8 +633,9 @@
}
static binder::Status createAppDataDirs(const std::string& path, int32_t uid, int32_t gid,
- int32_t* previousUid, int32_t cacheGid,
- const std::string& seInfo, mode_t targetMode) {
+ int32_t previousUid, int32_t cacheGid,
+ const std::string& seInfo, mode_t targetMode,
+ long projectIdApp, long projectIdCache) {
struct stat st{};
bool parent_dir_exists = (stat(path.c_str(), &st) == 0);
@@ -643,25 +645,17 @@
bool code_cache_exists = (access(code_cache_path.c_str(), F_OK) == 0);
if (parent_dir_exists) {
- if (*previousUid < 0) {
- // If previousAppId is -1 in CreateAppDataArgs, we will assume the current owner
- // of the directory as previousUid. This is required because it is not always possible
- // to chown app data during app upgrade (e.g. secondary users' CE storage not unlocked)
- *previousUid = st.st_uid;
- }
- if (*previousUid != uid) {
- if (!chown_app_dir(path, uid, *previousUid, cacheGid)) {
+ if (previousUid > 0 && previousUid != uid) {
+ if (!chown_app_dir(path, uid, previousUid, cacheGid)) {
return error("Failed to chown " + path);
}
}
}
// Prepare only the parent app directory
- long project_id_app = get_project_id(uid, PROJECT_ID_APP_START);
- long project_id_cache_app = get_project_id(uid, PROJECT_ID_APP_CACHE_START);
- if (prepare_app_dir(path, targetMode, uid, gid, project_id_app) ||
- prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid, project_id_cache_app) ||
- prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid, project_id_cache_app)) {
+ if (prepare_app_dir(path, targetMode, uid, gid, projectIdApp) ||
+ prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid, projectIdCache) ||
+ prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid, projectIdCache)) {
return error("Failed to prepare " + path);
}
@@ -702,12 +696,9 @@
int32_t uid = multiuser_get_uid(userId, appId);
- // If previousAppId < 0, we will use the existing app data owner as previousAppUid
- // If previousAppId == 0, we use uid as previousUid (no data migration will happen)
- // if previousAppId > 0, an app is upgrading and changing its app ID
- int32_t previousUid = previousAppId > 0
- ? (int32_t) multiuser_get_uid(userId, previousAppId)
- : (previousAppId == 0 ? uid : -1);
+ // If previousAppId > 0, an app is changing its app ID
+ int32_t previousUid =
+ previousAppId > 0 ? (int32_t)multiuser_get_uid(userId, previousAppId) : -1;
int32_t cacheGid = multiuser_get_cache_gid(userId, appId);
mode_t targetMode = targetSdkVersion >= MIN_RESTRICTED_HOME_SDK_VERSION ? 0700 : 0751;
@@ -717,10 +708,14 @@
cacheGid = uid;
}
+ long projectIdApp = get_project_id(uid, PROJECT_ID_APP_START);
+ long projectIdCache = get_project_id(uid, PROJECT_ID_APP_CACHE_START);
+
if (flags & FLAG_STORAGE_CE) {
auto path = create_data_user_ce_package_path(uuid_, userId, pkgname);
- auto status = createAppDataDirs(path, uid, uid, &previousUid, cacheGid, seInfo, targetMode);
+ auto status = createAppDataDirs(path, uid, uid, previousUid, cacheGid, seInfo, targetMode,
+ projectIdApp, projectIdCache);
if (!status.isOk()) {
return status;
}
@@ -745,11 +740,12 @@
if (flags & FLAG_STORAGE_DE) {
auto path = create_data_user_de_package_path(uuid_, userId, pkgname);
- auto status = createAppDataDirs(path, uid, uid, &previousUid, cacheGid, seInfo, targetMode);
+ auto status = createAppDataDirs(path, uid, uid, previousUid, cacheGid, seInfo, targetMode,
+ projectIdApp, projectIdCache);
if (!status.isOk()) {
return status;
}
- if (previousUid != uid) {
+ if (previousUid > 0 && previousUid != uid) {
chown_app_profile_dir(packageName, appId, userId);
}
@@ -945,8 +941,12 @@
}
const int32_t sandboxUid = multiuser_get_sdk_sandbox_uid(userId, appId);
int32_t previousSandboxUid = multiuser_get_sdk_sandbox_uid(userId, previousAppId);
- auto status = createAppDataDirs(path, sandboxUid, AID_NOBODY, &previousSandboxUid,
- cacheGid, seInfo, 0700 | S_ISGID);
+ int32_t appUid = multiuser_get_uid(userId, appId);
+ long projectIdApp = get_project_id(appUid, PROJECT_ID_APP_START);
+ long projectIdCache = get_project_id(appUid, PROJECT_ID_APP_CACHE_START);
+ auto status =
+ createAppDataDirs(path, sandboxUid, AID_NOBODY, previousSandboxUid, cacheGid,
+ seInfo, 0700 | S_ISGID, projectIdApp, projectIdCache);
if (!status.isOk()) {
res = status;
continue;
@@ -1176,6 +1176,25 @@
return res;
}
+binder::Status InstalldNativeService::deleteReferenceProfile(const std::string& packageName,
+ const std::string& profileName) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ LOCK_PACKAGE();
+
+ // This function only supports primary dex'es.
+ std::string path =
+ create_reference_profile_path(packageName, profileName, /*is_secondary_dex=*/false);
+ if (unlink(path.c_str()) != 0) {
+ if (errno == ENOENT) {
+ return ok();
+ } else {
+ return error("Failed to delete profile " + profileName + " for " + packageName);
+ }
+ }
+ return ok();
+}
+
binder::Status InstalldNativeService::destroyAppData(const std::optional<std::string>& uuid,
const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode) {
ENFORCE_UID(AID_SYSTEM);
@@ -2957,13 +2976,15 @@
// Dumps the contents of a profile file, using pkgname's dex files for pretty
// printing the result.
binder::Status InstalldNativeService::dumpProfiles(int32_t uid, const std::string& packageName,
- const std::string& profileName, const std::string& codePath, bool* _aidl_return) {
+ const std::string& profileName,
+ const std::string& codePath,
+ bool dumpClassesAndMethods, bool* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
CHECK_ARGUMENT_PATH(codePath);
LOCK_PACKAGE();
- *_aidl_return = dump_profiles(uid, packageName, profileName, codePath);
+ *_aidl_return = dump_profiles(uid, packageName, profileName, codePath, dumpClassesAndMethods);
return ok();
}
@@ -3410,7 +3431,7 @@
auto temp_path = StringPrintf("%smisc/installd/ioctl_check", android_data_dir.c_str());
if (access(temp_path.c_str(), F_OK) != 0) {
int fd = open(temp_path.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_CLOEXEC, 0644);
- result = set_quota_project_id(temp_path, 0, true) == 0;
+ result = set_quota_project_id(temp_path, 0, false) == 0;
close(fd);
// delete the temp file
remove(temp_path.c_str());
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 87a9206..521afc3 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -134,12 +134,15 @@
binder::Status mergeProfiles(int32_t uid, const std::string& packageName,
const std::string& profileName, int* _aidl_return);
binder::Status dumpProfiles(int32_t uid, const std::string& packageName,
- const std::string& profileName, const std::string& codePath, bool* _aidl_return);
+ const std::string& profileName, const std::string& codePath,
+ bool dumpClassesAndMethods, bool* _aidl_return);
binder::Status copySystemProfile(const std::string& systemProfile,
int32_t uid, const std::string& packageName, const std::string& profileName,
bool* _aidl_return);
binder::Status clearAppProfiles(const std::string& packageName, const std::string& profileName);
binder::Status destroyAppProfiles(const std::string& packageName);
+ binder::Status deleteReferenceProfile(const std::string& packageName,
+ const std::string& profileName);
binder::Status createProfileSnapshot(int32_t appId, const std::string& packageName,
const std::string& profileName, const std::string& classpath, bool* _aidl_return);
diff --git a/cmds/installd/TEST_MAPPING b/cmds/installd/TEST_MAPPING
index 8ccab4c..fc4cfc9 100644
--- a/cmds/installd/TEST_MAPPING
+++ b/cmds/installd/TEST_MAPPING
@@ -32,7 +32,12 @@
"name": "CtsCompilationTestCases"
},
{
- "name": "SdkSandboxStorageHostTest"
+ "name": "SdkSandboxStorageHostTest",
+ "options": [
+ {
+ "exclude-annotation": "android.platform.test.annotations.LargeTest"
+ }
+ ]
}
]
}
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 79c02e8..9ad853b 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -77,11 +77,12 @@
int mergeProfiles(int uid, @utf8InCpp String packageName, @utf8InCpp String profileName);
boolean dumpProfiles(int uid, @utf8InCpp String packageName, @utf8InCpp String profileName,
- @utf8InCpp String codePath);
+ @utf8InCpp String codePath, boolean dumpClassesAndMethods);
boolean copySystemProfile(@utf8InCpp String systemProfile, int uid,
@utf8InCpp String packageName, @utf8InCpp String profileName);
void clearAppProfiles(@utf8InCpp String packageName, @utf8InCpp String profileName);
void destroyAppProfiles(@utf8InCpp String packageName);
+ void deleteReferenceProfile(@utf8InCpp String packageName, @utf8InCpp String profileName);
boolean createProfileSnapshot(int appId, @utf8InCpp String packageName,
@utf8InCpp String profileName, @utf8InCpp String classpath);
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 894c7d3..ebb7891 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -624,12 +624,15 @@
/*for_boot_image*/false);
}
- void SetupDump(const std::vector<unique_fd>& profiles_fd,
- const unique_fd& reference_profile_fd,
+ void SetupDump(const std::vector<unique_fd>& profiles_fd, const unique_fd& reference_profile_fd,
const std::vector<std::string>& dex_locations,
- const std::vector<unique_fd>& apk_fds,
+ const std::vector<unique_fd>& apk_fds, bool dump_classes_and_methods,
const unique_fd& output_fd) {
- AddArg("--dump-only");
+ if (dump_classes_and_methods) {
+ AddArg("--dump-classes-and-methods");
+ } else {
+ AddArg("--dump-only");
+ }
AddArg(StringPrintf("--dump-output-to-fd=%d", output_fd.get()));
SetupArgs(profiles_fd,
reference_profile_fd,
@@ -772,7 +775,7 @@
}
bool dump_profiles(int32_t uid, const std::string& pkgname, const std::string& profile_name,
- const std::string& code_path) {
+ const std::string& code_path, bool dump_classes_and_methods) {
std::vector<unique_fd> profile_fds;
unique_fd reference_profile_fd;
std::string out_file_name = StringPrintf("/data/misc/profman/%s-%s.txt",
@@ -808,7 +811,8 @@
RunProfman profman_dump;
- profman_dump.SetupDump(profile_fds, reference_profile_fd, dex_locations, apk_fds, output_fd);
+ profman_dump.SetupDump(profile_fds, reference_profile_fd, dex_locations, apk_fds,
+ dump_classes_and_methods, output_fd);
pid_t pid = fork();
if (pid == 0) {
/* child -- drop privileges before continuing */
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index f7af929..5cf402c 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -88,10 +88,8 @@
const std::string& profile_name,
const std::string& classpath);
-bool dump_profiles(int32_t uid,
- const std::string& pkgname,
- const std::string& profile_name,
- const std::string& code_path);
+bool dump_profiles(int32_t uid, const std::string& pkgname, const std::string& profile_name,
+ const std::string& code_path, bool dump_classes_and_methods);
bool copy_system_profile(const std::string& system_profile,
uid_t packageUid,
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index 38cb370..f86f1d5 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -465,7 +465,7 @@
EXPECT_TRUE(create_cache_path(buf, "/path/to/file.apk", "isa"));
EXPECT_EQ("/data/dalvik-cache/isa/path@to@file.apk@classes.dex", std::string(buf));
}
-TEST_F(ServiceTest, GetAppSize) {
+TEST_F(ServiceTest, GetAppSizeManualForMedia) {
struct stat s;
std::string externalPicDir =
@@ -509,6 +509,7 @@
system(removeCommand.c_str());
}
}
+
TEST_F(ServiceTest, GetAppSizeWrongSizes) {
int32_t externalStorageAppId = -1;
std::vector<int64_t> externalStorageSize;
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 9801a9b..45aeab6 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -707,16 +707,16 @@
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())) {
+ auto dir_to_delete = temp_dir_path.c_str();
+ if (::rename(pathname.c_str(), dir_to_delete)) {
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;
+ ALOGE("Couldn't rename %s -> %s: %s \n", pathname.c_str(), dir_to_delete, strerror(errno));
+ dir_to_delete = pathname.c_str();
}
- return delete_dir_contents(temp_dir_path.c_str(), 1, exclusion_predicate, ignore_if_missing);
+ return delete_dir_contents(dir_to_delete, 1, exclusion_predicate, ignore_if_missing);
}
bool is_renamed_deleted_dir(const std::string& path) {
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 5003151..bdd5172 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -227,6 +227,12 @@
}
prebuilt_etc {
+ name: "android.software.opengles.deqp.level-2022-03-01.prebuilt.xml",
+ src: "android.software.opengles.deqp.level-2022-03-01.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
name: "android.software.sip.voip.prebuilt.xml",
src: "android.software.sip.voip.xml",
defaults: ["frameworks_native_data_etc_defaults"],
@@ -245,6 +251,12 @@
}
prebuilt_etc {
+ name: "android.software.vulkan.deqp.level-2022-03-01.prebuilt.xml",
+ src: "android.software.vulkan.deqp.level-2022-03-01.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
name: "aosp_excluded_hardware.prebuilt.xml",
src: "aosp_excluded_hardware.xml",
defaults: ["frameworks_native_data_etc_defaults"],
diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h
index 4c83a14..ee392fc 100644
--- a/include/android/multinetwork.h
+++ b/include/android/multinetwork.h
@@ -235,7 +235,7 @@
*
* Available since API level 33.
*/
-int android_tag_socket_with_uid(int sockfd, int tag, uid_t uid) __INTRODUCED_IN(33);
+int android_tag_socket_with_uid(int sockfd, uint32_t tag, uid_t uid) __INTRODUCED_IN(33);
/*
* Set the socket tag for traffic statistics on the specified socket.
@@ -245,14 +245,26 @@
* opened by another UID or was previously tagged by another UID. Subsequent
* calls always replace any existing parameters. The socket tag is kept when the
* socket is sent to another process using binder IPCs or other mechanisms such
- * as UNIX socket fd passing.
+ * as UNIX socket fd passing. The tag is a value defined by the caller and used
+ * together with uid for data traffic accounting, so that the function callers
+ * can account different types of data usage for a uid.
*
* Returns 0 on success, or a negative POSIX error code (see errno.h) on
* failure.
*
+ * Some possible error codes:
+ * -EBADF Bad socketfd.
+ * -EPERM No permission.
+ * -EAFNOSUPPORT Socket family is neither AF_INET nor AF_INET6.
+ * -EPROTONOSUPPORT Socket protocol is neither IPPROTO_UDP nor IPPROTO_TCP.
+ * -EMFILE Too many stats entries.
+ * There are still other error codes that may provided by -errno of
+ * [getsockopt()](https://man7.org/linux/man-pages/man2/getsockopt.2.html) or by
+ * BPF maps read/write sys calls, which are set appropriately.
+ *
* Available since API level 33.
*/
-int android_tag_socket(int sockfd, int tag) __INTRODUCED_IN(33);
+int android_tag_socket(int sockfd, uint32_t tag) __INTRODUCED_IN(33);
/*
* Untag a network socket.
@@ -267,6 +279,12 @@
* Returns 0 on success, or a negative POSIX error code (see errno.h) on
* failure.
*
+ * One of possible error code:
+ * -EBADF Bad socketfd.
+ * Other error codes are either provided by -errno of
+ * [getsockopt()](https://man7.org/linux/man-pages/man2/getsockopt.2.html) or by
+ * BPF map element deletion sys call, which are set appropriately.
+ *
* Available since API level 33.
*/
int android_untag_socket(int sockfd) __INTRODUCED_IN(33);
diff --git a/include/android/sensor.h b/include/android/sensor.h
index c714b05..6112d5f 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -213,6 +213,13 @@
*/
ASENSOR_TYPE_HEART_BEAT = 31,
/**
+ * A constant describing a dynamic sensor meta event sensor.
+ *
+ * A sensor event of this type is received when a dynamic sensor is added to or removed from
+ * the system. This sensor type should always use special trigger report mode.
+ */
+ ASENSOR_TYPE_DYNAMIC_SENSOR_META = 32,
+ /**
* This sensor type is for delivering additional sensor information aside
* from sensor event data.
*
@@ -761,6 +768,10 @@
* Each time this is called, the previously returned list is deallocated and
* must no longer be used.
*
+ * Clients should call this if they receive a sensor update from
+ * {@link ASENSOR_TYPE_DYNAMIC_SENSOR_META} indicating the sensors have changed.
+ * If this happens, previously received lists from this method will be stale.
+ *
* Available since API level 33.
*
* \param manager the {@link ASensorManager} instance obtained from
diff --git a/include/ftl/enum.h b/include/ftl/enum.h
index 5234c05..82af1d6 100644
--- a/include/ftl/enum.h
+++ b/include/ftl/enum.h
@@ -261,10 +261,10 @@
const auto value = to_underlying(v);
// TODO: Replace with std::popcount and std::countr_zero in C++20.
- if (__builtin_popcountl(value) != 1) return {};
+ if (__builtin_popcountll(value) != 1) return {};
constexpr auto kRange = details::EnumRange<E, details::FlagName>{};
- return kRange.values[__builtin_ctzl(value)];
+ return kRange.values[__builtin_ctzll(value)];
}
// Returns a stringified enumerator, or its integral value if not named.
diff --git a/include/ftl/fake_guard.h b/include/ftl/fake_guard.h
new file mode 100644
index 0000000..bacd1b2
--- /dev/null
+++ b/include/ftl/fake_guard.h
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#define FTL_ATTRIBUTE(a) __attribute__((a))
+
+namespace android::ftl {
+
+// Granular alternative to [[clang::no_thread_safety_analysis]]. Given a std::mutex-like object,
+// FakeGuard suppresses enforcement of thread-safe access to guarded variables within its scope.
+// While FakeGuard is scoped to a block, there are macro shorthands for a single expression, as
+// well as function/lambda scope (though calls must be indirect, e.g. virtual or std::function):
+//
+// struct {
+// std::mutex mutex;
+// int x FTL_ATTRIBUTE(guarded_by(mutex)) = -1;
+//
+// int f() {
+// {
+// ftl::FakeGuard guard(mutex);
+// x = 0;
+// }
+//
+// return FTL_FAKE_GUARD(mutex, x + 1);
+// }
+//
+// std::function<int()> g() const {
+// return [this]() FTL_FAKE_GUARD(mutex) { return x; };
+// }
+// } s;
+//
+// assert(s.f() == 1);
+// assert(s.g()() == 0);
+//
+// An example of a situation where FakeGuard helps is a mutex that guards writes on Thread 1, and
+// reads on Thread 2. Reads on Thread 1, which is the only writer, need not be under lock, so can
+// use FakeGuard to appease the thread safety analyzer. Another example is enforcing and documenting
+// exclusive access by a single thread. This is done by defining a global constant that represents a
+// thread context, and annotating guarded variables as if it were a mutex (though without any effect
+// at run time):
+//
+// constexpr class [[clang::capability("mutex")]] {
+// } kMainThreadContext;
+//
+template <typename Mutex>
+struct [[clang::scoped_lockable]] FakeGuard final {
+ explicit FakeGuard(const Mutex& mutex) FTL_ATTRIBUTE(acquire_capability(mutex)) {}
+ [[clang::release_capability()]] ~FakeGuard() {}
+
+ FakeGuard(const FakeGuard&) = delete;
+ FakeGuard& operator=(const FakeGuard&) = delete;
+};
+
+} // namespace android::ftl
+
+// TODO: Enable in C++23 once standard attributes can be used on lambdas.
+#if 0
+#define FTL_FAKE_GUARD1(mutex) [[using clang: acquire_capability(mutex), release_capability(mutex)]]
+#else
+#define FTL_FAKE_GUARD1(mutex) \
+ FTL_ATTRIBUTE(acquire_capability(mutex)) \
+ FTL_ATTRIBUTE(release_capability(mutex))
+#endif
+
+// The parentheses around `expr` are needed to deduce an lvalue or rvalue reference.
+#define FTL_FAKE_GUARD2(mutex, expr) \
+ [&]() -> decltype(auto) { \
+ const android::ftl::FakeGuard guard(mutex); \
+ return (expr); \
+ }()
+
+#define FTL_MAKE_FAKE_GUARD(arg1, arg2, guard, ...) guard
+
+// The void argument suppresses a warning about zero variadic macro arguments.
+#define FTL_FAKE_GUARD(...) \
+ FTL_MAKE_FAKE_GUARD(__VA_ARGS__, FTL_FAKE_GUARD2, FTL_FAKE_GUARD1, void)(__VA_ARGS__)
diff --git a/include/ftl/Flags.h b/include/ftl/flags.h
similarity index 81%
rename from include/ftl/Flags.h
rename to include/ftl/flags.h
index 708eaf5..70aaa0e 100644
--- a/include/ftl/Flags.h
+++ b/include/ftl/flags.h
@@ -19,16 +19,15 @@
#include <ftl/enum.h>
#include <ftl/string.h>
+#include <bitset>
#include <cstdint>
#include <iterator>
#include <string>
#include <type_traits>
-#include "utils/BitSet.h"
+// TODO(b/185536303): Align with FTL style.
-// TODO(b/185536303): Align with FTL style and namespace.
-
-namespace android {
+namespace android::ftl {
/* A class for handling flags defined by an enum or enum class in a type-safe way. */
template <typename F>
@@ -49,28 +48,29 @@
// should force them to be explicitly constructed from their underlying types to make full use
// of the type checker.
template <typename T = U>
- constexpr Flags(T t, std::enable_if_t<!ftl::is_scoped_enum_v<F>, T>* = nullptr) : mFlags(t) {}
+ constexpr Flags(T t, std::enable_if_t<!is_scoped_enum_v<F>, T>* = nullptr) : mFlags(t) {}
template <typename T = U>
- explicit constexpr Flags(T t, std::enable_if_t<ftl::is_scoped_enum_v<F>, T>* = nullptr)
+ explicit constexpr Flags(T t, std::enable_if_t<is_scoped_enum_v<F>, T>* = nullptr)
: mFlags(t) {}
class Iterator {
- // The type can't be larger than 64-bits otherwise it won't fit in BitSet64.
- static_assert(sizeof(U) <= sizeof(uint64_t));
+ using Bits = std::uint64_t;
+ static_assert(sizeof(U) <= sizeof(Bits));
public:
+ constexpr Iterator() = default;
Iterator(Flags<F> flags) : mRemainingFlags(flags.mFlags) { (*this)++; }
- Iterator() : mRemainingFlags(0), mCurrFlag(static_cast<F>(0)) {}
// Pre-fix ++
Iterator& operator++() {
- if (mRemainingFlags.isEmpty()) {
- mCurrFlag = static_cast<F>(0);
+ if (mRemainingFlags.none()) {
+ mCurrFlag = 0;
} else {
- uint64_t bit = mRemainingFlags.clearLastMarkedBit(); // counts from left
- const U flag = 1 << (64 - bit - 1);
- mCurrFlag = static_cast<F>(flag);
+ // TODO: Replace with std::countr_zero in C++20.
+ const Bits bit = static_cast<Bits>(__builtin_ctzll(mRemainingFlags.to_ullong()));
+ mRemainingFlags.reset(static_cast<std::size_t>(bit));
+ mCurrFlag = static_cast<U>(static_cast<Bits>(1) << bit);
}
return *this;
}
@@ -88,7 +88,7 @@
bool operator!=(Iterator other) const { return !(*this == other); }
- F operator*() { return mCurrFlag; }
+ F operator*() const { return F{mCurrFlag}; }
// iterator traits
@@ -107,8 +107,8 @@
using pointer = void;
private:
- BitSet64 mRemainingFlags;
- F mCurrFlag;
+ std::bitset<sizeof(Bits) * 8> mRemainingFlags;
+ U mCurrFlag = 0;
};
/*
@@ -175,7 +175,7 @@
bool first = true;
U unstringified = 0;
for (const F f : *this) {
- if (const auto flagName = ftl::flag_name(f)) {
+ if (const auto flagName = flag_name(f)) {
appendFlag(result, flagName.value(), first);
} else {
unstringified |= static_cast<U>(f);
@@ -183,8 +183,8 @@
}
if (unstringified != 0) {
- constexpr auto radix = sizeof(U) == 1 ? ftl::Radix::kBin : ftl::Radix::kHex;
- appendFlag(result, ftl::to_string(unstringified, radix), first);
+ constexpr auto radix = sizeof(U) == 1 ? Radix::kBin : Radix::kHex;
+ appendFlag(result, to_string(unstringified, radix), first);
}
if (first) {
@@ -211,15 +211,15 @@
// as flags. In order to use these, add them via a `using namespace` declaration.
namespace flag_operators {
-template <typename F, typename = std::enable_if_t<ftl::is_scoped_enum_v<F>>>
+template <typename F, typename = std::enable_if_t<is_scoped_enum_v<F>>>
inline Flags<F> operator~(F f) {
- return static_cast<F>(~ftl::to_underlying(f));
+ return static_cast<F>(~to_underlying(f));
}
-template <typename F, typename = std::enable_if_t<ftl::is_scoped_enum_v<F>>>
+template <typename F, typename = std::enable_if_t<is_scoped_enum_v<F>>>
Flags<F> operator|(F lhs, F rhs) {
- return static_cast<F>(ftl::to_underlying(lhs) | ftl::to_underlying(rhs));
+ return static_cast<F>(to_underlying(lhs) | to_underlying(rhs));
}
} // namespace flag_operators
-} // namespace android
+} // namespace android::ftl
diff --git a/include/input/PrintTools.h b/include/input/PrintTools.h
new file mode 100644
index 0000000..7c3b29b
--- /dev/null
+++ b/include/input/PrintTools.h
@@ -0,0 +1,61 @@
+/*
+ * 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 <map>
+#include <set>
+#include <string>
+
+namespace android {
+
+template <typename T>
+std::string constToString(const T& v) {
+ return std::to_string(v);
+}
+
+/**
+ * Convert a set of integral types to string.
+ */
+template <typename T>
+std::string dumpSet(const std::set<T>& v, std::string (*toString)(const T&) = constToString) {
+ std::string out;
+ for (const T& entry : v) {
+ out += out.empty() ? "{" : ", ";
+ out += toString(entry);
+ }
+ return out.empty() ? "{}" : (out + "}");
+}
+
+/**
+ * Convert a map to string. Both keys and values of the map should be integral type.
+ */
+template <typename K, typename V>
+std::string dumpMap(const std::map<K, V>& map, std::string (*keyToString)(const K&) = constToString,
+ std::string (*valueToString)(const V&) = constToString) {
+ std::string out;
+ for (const auto& [k, v] : map) {
+ if (!out.empty()) {
+ out += "\n";
+ }
+ out += keyToString(k) + ":" + valueToString(v);
+ }
+ return out;
+}
+
+const char* toString(bool value);
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 01b25d3..39befbe 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -582,6 +582,10 @@
BBinder::~BBinder()
{
+ if (!wasParceled() && getExtension()) {
+ ALOGW("Binder %p destroyed with extension attached before being parceled.", this);
+ }
+
Extras* e = mExtras.load(std::memory_order_relaxed);
if (e) delete e;
}
diff --git a/libs/binder/IUidObserver.cpp b/libs/binder/IUidObserver.cpp
index a1b08db..d952dc7 100644
--- a/libs/binder/IUidObserver.cpp
+++ b/libs/binder/IUidObserver.cpp
@@ -57,8 +57,7 @@
}
virtual void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq,
- int32_t capability)
- {
+ int32_t capability) {
Parcel data, reply;
data.writeInterfaceToken(IUidObserver::getInterfaceDescriptor());
data.writeInt32((int32_t) uid);
@@ -67,6 +66,12 @@
data.writeInt32(capability);
remote()->transact(ON_UID_STATE_CHANGED_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY);
}
+
+ virtual void onUidProcAdjChanged(uid_t uid) {
+ Parcel data, reply;
+ data.writeInt32((int32_t)uid);
+ remote()->transact(ON_UID_PROC_ADJ_CHANGED_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY);
+ }
};
// ----------------------------------------------------------------------
@@ -102,6 +107,7 @@
onUidIdle(uid, disabled);
return NO_ERROR;
} break;
+
case ON_UID_STATE_CHANGED_TRANSACTION: {
CHECK_INTERFACE(IUidObserver, data, reply);
uid_t uid = data.readInt32();
@@ -111,6 +117,14 @@
onUidStateChanged(uid, procState, procStateSeq, capability);
return NO_ERROR;
} break;
+
+ case ON_UID_PROC_ADJ_CHANGED_TRANSACTION: {
+ CHECK_INTERFACE(IUidObserver, data, reply);
+ uid_t uid = data.readInt32();
+ onUidProcAdjChanged(uid);
+ return NO_ERROR;
+ } break;
+
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index be50a75..58b0b35 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -1584,6 +1584,7 @@
template<class T>
status_t Parcel::readAligned(T *pArg) const {
static_assert(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
+ static_assert(std::is_trivially_copyable_v<T>);
if ((mDataPos+sizeof(T)) <= mDataSize) {
if (mObjectsSize > 0) {
@@ -1595,9 +1596,8 @@
}
}
- const void* data = mData+mDataPos;
+ memcpy(pArg, mData + mDataPos, sizeof(T));
mDataPos += sizeof(T);
- *pArg = *reinterpret_cast<const T*>(data);
return NO_ERROR;
} else {
return NOT_ENOUGH_DATA;
@@ -1617,10 +1617,11 @@
template<class T>
status_t Parcel::writeAligned(T val) {
static_assert(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
+ static_assert(std::is_trivially_copyable_v<T>);
if ((mDataPos+sizeof(val)) <= mDataCapacity) {
restart_write:
- *reinterpret_cast<T*>(mData+mDataPos) = val;
+ memcpy(mData + mDataPos, &val, sizeof(val));
return finishWrite(sizeof(val));
}
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index 2e7084e..6d89064 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -313,7 +313,8 @@
const sp<RpcSession>& session, const char* what, iovec* iovs, int niovs,
const std::function<status_t()>& altPoll) {
for (int i = 0; i < niovs; i++) {
- LOG_RPC_DETAIL("Sending %s on RpcTransport %p: %s", what, connection->rpcTransport.get(),
+ LOG_RPC_DETAIL("Sending %s (part %d of %d) on RpcTransport %p: %s",
+ what, i + 1, niovs, connection->rpcTransport.get(),
android::base::HexString(iovs[i].iov_base, iovs[i].iov_len).c_str());
}
@@ -343,7 +344,8 @@
}
for (int i = 0; i < niovs; i++) {
- LOG_RPC_DETAIL("Received %s on RpcTransport %p: %s", what, connection->rpcTransport.get(),
+ LOG_RPC_DETAIL("Received %s (part %d of %d) on RpcTransport %p: %s",
+ what, i + 1, niovs, connection->rpcTransport.get(),
android::base::HexString(iovs[i].iov_base, iovs[i].iov_len).c_str());
}
return OK;
@@ -660,8 +662,14 @@
status_t RpcState::drainCommands(const sp<RpcSession::RpcConnection>& connection,
const sp<RpcSession>& session, CommandType type) {
uint8_t buf;
- while (connection->rpcTransport->peek(&buf, sizeof(buf)).value_or(0) > 0) {
- status_t status = getAndExecuteCommand(connection, session, type);
+ while (true) {
+ size_t num_bytes;
+ status_t status = connection->rpcTransport->peek(&buf, sizeof(buf), &num_bytes);
+ if (status == WOULD_BLOCK) break;
+ if (status != OK) return status;
+ if (!num_bytes) break;
+
+ status = getAndExecuteCommand(connection, session, type);
if (status != OK) return status;
}
return OK;
diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp
index 636e5d0..7cfc780 100644
--- a/libs/binder/RpcTransportRaw.cpp
+++ b/libs/binder/RpcTransportRaw.cpp
@@ -24,9 +24,6 @@
#include "FdTrigger.h"
#include "RpcState.h"
-using android::base::ErrnoError;
-using android::base::Result;
-
namespace android {
namespace {
@@ -35,12 +32,20 @@
class RpcTransportRaw : public RpcTransport {
public:
explicit RpcTransportRaw(android::base::unique_fd socket) : mSocket(std::move(socket)) {}
- Result<size_t> peek(void *buf, size_t size) override {
+ status_t peek(void* buf, size_t size, size_t* out_size) override {
ssize_t ret = TEMP_FAILURE_RETRY(::recv(mSocket.get(), buf, size, MSG_PEEK));
if (ret < 0) {
- return ErrnoError() << "recv(MSG_PEEK)";
+ int savedErrno = errno;
+ if (savedErrno == EAGAIN || savedErrno == EWOULDBLOCK) {
+ return WOULD_BLOCK;
+ }
+
+ LOG_RPC_DETAIL("RpcTransport peek(): %s", strerror(savedErrno));
+ return -savedErrno;
}
- return ret;
+
+ *out_size = static_cast<size_t>(ret);
+ return OK;
}
template <typename SendOrReceive>
diff --git a/libs/binder/RpcTransportTls.cpp b/libs/binder/RpcTransportTls.cpp
index 3936204..bc68c37 100644
--- a/libs/binder/RpcTransportTls.cpp
+++ b/libs/binder/RpcTransportTls.cpp
@@ -37,10 +37,6 @@
#define LOG_TLS_DETAIL(...) ALOGV(__VA_ARGS__) // for type checking
#endif
-using android::base::ErrnoError;
-using android::base::Error;
-using android::base::Result;
-
namespace android {
namespace {
@@ -165,17 +161,8 @@
return ret;
}
- // |sslError| should be from Ssl::getError().
- // If |sslError| is WANT_READ / WANT_WRITE, poll for POLLIN / POLLOUT respectively. Otherwise
- // return error. Also return error if |fdTrigger| is triggered before or during poll().
- status_t pollForSslError(android::base::borrowed_fd fd, int sslError, FdTrigger* fdTrigger,
- const char* fnString, int additionalEvent,
- const std::function<status_t()>& altPoll) {
+ status_t toStatus(int sslError, const char* fnString) {
switch (sslError) {
- case SSL_ERROR_WANT_READ:
- return handlePoll(POLLIN | additionalEvent, fd, fdTrigger, fnString, altPoll);
- case SSL_ERROR_WANT_WRITE:
- return handlePoll(POLLOUT | additionalEvent, fd, fdTrigger, fnString, altPoll);
case SSL_ERROR_SYSCALL: {
auto queue = toString();
LOG_TLS_DETAIL("%s(): %s. Treating as DEAD_OBJECT. Error queue: %s", fnString,
@@ -191,6 +178,22 @@
}
}
+ // |sslError| should be from Ssl::getError().
+ // If |sslError| is WANT_READ / WANT_WRITE, poll for POLLIN / POLLOUT respectively. Otherwise
+ // return error. Also return error if |fdTrigger| is triggered before or during poll().
+ status_t pollForSslError(android::base::borrowed_fd fd, int sslError, FdTrigger* fdTrigger,
+ const char* fnString, int additionalEvent,
+ const std::function<status_t()>& altPoll) {
+ switch (sslError) {
+ case SSL_ERROR_WANT_READ:
+ return handlePoll(POLLIN | additionalEvent, fd, fdTrigger, fnString, altPoll);
+ case SSL_ERROR_WANT_WRITE:
+ return handlePoll(POLLOUT | additionalEvent, fd, fdTrigger, fnString, altPoll);
+ default:
+ return toStatus(sslError, fnString);
+ }
+ }
+
private:
bool mHandled = false;
@@ -274,7 +277,7 @@
public:
RpcTransportTls(android::base::unique_fd socket, Ssl ssl)
: mSocket(std::move(socket)), mSsl(std::move(ssl)) {}
- Result<size_t> peek(void* buf, size_t size) override;
+ status_t peek(void* buf, size_t size, size_t* out_size) override;
status_t interruptableWriteFully(FdTrigger* fdTrigger, iovec* iovs, int niovs,
const std::function<status_t()>& altPoll) override;
status_t interruptableReadFully(FdTrigger* fdTrigger, iovec* iovs, int niovs,
@@ -286,7 +289,7 @@
};
// Error code is errno.
-Result<size_t> RpcTransportTls::peek(void* buf, size_t size) {
+status_t RpcTransportTls::peek(void* buf, size_t size, size_t* out_size) {
size_t todo = std::min<size_t>(size, std::numeric_limits<int>::max());
auto [ret, errorQueue] = mSsl.call(SSL_peek, buf, static_cast<int>(todo));
if (ret < 0) {
@@ -294,13 +297,15 @@
if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
// Seen EAGAIN / EWOULDBLOCK on recv(2) / send(2).
// Like RpcTransportRaw::peek(), don't handle it here.
- return Error(EWOULDBLOCK) << "SSL_peek(): " << errorQueue.toString();
+ errorQueue.clear();
+ return WOULD_BLOCK;
}
- return Error() << "SSL_peek(): " << errorQueue.toString();
+ return errorQueue.toStatus(err, "SSL_peek");
}
errorQueue.clear();
LOG_TLS_DETAIL("TLS: Peeked %d bytes!", ret);
- return ret;
+ *out_size = static_cast<size_t>(ret);
+ return OK;
}
status_t RpcTransportTls::interruptableWriteFully(FdTrigger* fdTrigger, iovec* iovs, int niovs,
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index aaa812b..6b31812 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -77,7 +77,7 @@
* have
*/
[[nodiscard]] status_t setupInetServer(const char* address, unsigned int port,
- unsigned int* assignedPort);
+ unsigned int* assignedPort = nullptr);
/**
* If setup*Server has been successful, return true. Otherwise return false.
diff --git a/libs/binder/include/binder/RpcTransport.h b/libs/binder/include/binder/RpcTransport.h
index ade2d94..751c4f9 100644
--- a/libs/binder/include/binder/RpcTransport.h
+++ b/libs/binder/include/binder/RpcTransport.h
@@ -22,7 +22,6 @@
#include <memory>
#include <string>
-#include <android-base/result.h>
#include <android-base/unique_fd.h>
#include <utils/Errors.h>
@@ -41,7 +40,7 @@
virtual ~RpcTransport() = default;
// replacement of ::recv(MSG_PEEK). Error code may not be set if TLS is enabled.
- [[nodiscard]] virtual android::base::Result<size_t> peek(void *buf, size_t size) = 0;
+ [[nodiscard]] virtual status_t peek(void *buf, size_t size, size_t *out_size) = 0;
/**
* Read (or write), but allow to be interrupted by a trigger.
diff --git a/libs/binder/include_activitymanager/binder/ActivityManager.h b/libs/binder/include_activitymanager/binder/ActivityManager.h
index abc7f1d..5dfbd44 100644
--- a/libs/binder/include_activitymanager/binder/ActivityManager.h
+++ b/libs/binder/include_activitymanager/binder/ActivityManager.h
@@ -31,20 +31,21 @@
class ActivityManager
{
public:
-
enum {
// Flag for registerUidObserver: report uid state changed
- UID_OBSERVER_PROCSTATE = 1<<0,
+ UID_OBSERVER_PROCSTATE = 1 << 0,
// Flag for registerUidObserver: report uid gone
- UID_OBSERVER_GONE = 1<<1,
+ UID_OBSERVER_GONE = 1 << 1,
// Flag for registerUidObserver: report uid has become idle
- UID_OBSERVER_IDLE = 1<<2,
+ UID_OBSERVER_IDLE = 1 << 2,
// Flag for registerUidObserver: report uid has become active
- UID_OBSERVER_ACTIVE = 1<<3,
+ UID_OBSERVER_ACTIVE = 1 << 3,
// Flag for registerUidObserver: report uid cached state has changed
- UID_OBSERVER_CACHED = 1<<4,
+ UID_OBSERVER_CACHED = 1 << 4,
// Flag for registerUidObserver: report uid capability has changed
- UID_OBSERVER_CAPABILITY = 1<<5,
+ UID_OBSERVER_CAPABILITY = 1 << 5,
+ // Flag for registerUidObserver: report pid oom adj has changed
+ UID_OBSERVER_PROC_OOM_ADJ = 1 << 6,
};
// PROCESS_STATE_* must come from frameworks/base/core/java/android/app/ProcessStateEnum.aidl.
diff --git a/libs/binder/include_activitymanager/binder/IUidObserver.h b/libs/binder/include_activitymanager/binder/IUidObserver.h
index 9291c0b..17f03a9 100644
--- a/libs/binder/include_activitymanager/binder/IUidObserver.h
+++ b/libs/binder/include_activitymanager/binder/IUidObserver.h
@@ -33,13 +33,15 @@
virtual void onUidActive(uid_t uid) = 0;
virtual void onUidIdle(uid_t uid, bool disabled) = 0;
virtual void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq,
- int32_t capability) = 0;
+ int32_t capability) = 0;
+ virtual void onUidProcAdjChanged(uid_t uid) = 0;
enum {
ON_UID_GONE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
ON_UID_ACTIVE_TRANSACTION,
ON_UID_IDLE_TRANSACTION,
- ON_UID_STATE_CHANGED_TRANSACTION
+ ON_UID_STATE_CHANGED_TRANSACTION,
+ ON_UID_PROC_ADJ_CHANGED_TRANSACTION
};
};
diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
index b3bc7f4..c8e78fc 100644
--- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
@@ -324,4 +324,42 @@
} // namespace ndk
+// Once minSdkVersion is 30, we are guaranteed to be building with the
+// Android 11 AIDL compiler which supports the SharedRefBase::make API.
+#if !defined(__ANDROID_API__) || __ANDROID_API__ >= 30 || defined(__ANDROID_APEX__)
+namespace ndk::internal {
+template <typename T, typename = void>
+struct is_complete_type : std::false_type {};
+
+template <typename T>
+struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};
+} // namespace ndk::internal
+
+namespace std {
+
+// Define `SharedRefBase` specific versions of `std::make_shared` and
+// `std::make_unique` to block people from using them. Using them to allocate
+// `ndk::SharedRefBase` objects results in double ownership. Use
+// `ndk::SharedRefBase::make<T>(...)` instead.
+//
+// Note: We exclude incomplete types because `std::is_base_of` is undefined in
+// that case.
+
+template <typename T, typename... Args,
+ std::enable_if_t<ndk::internal::is_complete_type<T>::value, bool> = true,
+ std::enable_if_t<std::is_base_of<ndk::SharedRefBase, T>::value, bool> = true>
+shared_ptr<T> make_shared(Args...) { // SEE COMMENT ABOVE.
+ static_assert(!std::is_base_of<ndk::SharedRefBase, T>::value);
+}
+
+template <typename T, typename... Args,
+ std::enable_if_t<ndk::internal::is_complete_type<T>::value, bool> = true,
+ std::enable_if_t<std::is_base_of<ndk::SharedRefBase, T>::value, bool> = true>
+unique_ptr<T> make_unique(Args...) { // SEE COMMENT ABOVE.
+ static_assert(!std::is_base_of<ndk::SharedRefBase, T>::value);
+}
+
+} // namespace std
+#endif
+
/** @} */
diff --git a/libs/binder/ndk/include_platform/android/binder_stability.h b/libs/binder/ndk/include_platform/android/binder_stability.h
index f113ba8..d0cd11f 100644
--- a/libs/binder/ndk/include_platform/android/binder_stability.h
+++ b/libs/binder/ndk/include_platform/android/binder_stability.h
@@ -97,6 +97,10 @@
*
* This interface has system<->vendor stability
*/
+// b/227835797 - can't use __INTRODUCED_IN(30) because old targets load this code
+#if __ANDROID_MIN_SDK_VERSION__ < 30
+__attribute__((weak))
+#endif // __ANDROID_MIN_SDK_VERSION__ < 30
void AIBinder_markVintfStability(AIBinder* binder);
__END_DECLS
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 357b454..1b136dc 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -231,8 +231,7 @@
}
TEST(NdkBinder, DetectNoSharedRefBaseCreated) {
- EXPECT_DEATH(std::make_shared<MyBinderNdkUnitTest>(),
- "SharedRefBase: no ref created during lifetime");
+ EXPECT_DEATH(MyBinderNdkUnitTest(), "SharedRefBase: no ref created during lifetime");
}
TEST(NdkBinder, GetServiceThatDoesntExist) {
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index e3e4730..4df557b 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -575,6 +575,20 @@
cookie_decr_refcount: unsafe extern "C" fn(*mut c_void),
}
+/// # Safety
+///
+/// A `DeathRecipient` is a wrapper around `AIBinder_DeathRecipient` and a pointer
+/// to a `Fn` which is `Sync` and `Send` (the cookie field). As
+/// `AIBinder_DeathRecipient` is threadsafe, this structure is too.
+unsafe impl Send for DeathRecipient {}
+
+/// # Safety
+///
+/// A `DeathRecipient` is a wrapper around `AIBinder_DeathRecipient` and a pointer
+/// to a `Fn` which is `Sync` and `Send` (the cookie field). As
+/// `AIBinder_DeathRecipient` is threadsafe, this structure is too.
+unsafe impl Sync for DeathRecipient {}
+
impl DeathRecipient {
/// Create a new death recipient that will call the given callback when its
/// associated object dies.
diff --git a/libs/binder/tests/binderBinderUnitTest.cpp b/libs/binder/tests/binderBinderUnitTest.cpp
index 1be0c59..ce2770f 100644
--- a/libs/binder/tests/binderBinderUnitTest.cpp
+++ b/libs/binder/tests/binderBinderUnitTest.cpp
@@ -41,3 +41,10 @@
EXPECT_EQ(kObject1, binder->detachObject(kObjectId1));
EXPECT_EQ(nullptr, binder->attachObject(kObjectId1, kObject2, nullptr, nullptr));
}
+
+TEST(Binder, AttachExtension) {
+ auto binder = sp<BBinder>::make();
+ auto ext = sp<BBinder>::make();
+ binder->setExtension(ext);
+ EXPECT_EQ(ext, binder->getExtension());
+}
diff --git a/libs/binder/tests/include_tls_test_utils/binder/RpcTlsTestUtils.h b/libs/binder/tests/include_tls_test_utils/binder/RpcTlsTestUtils.h
index 094addd..50d12c4 100644
--- a/libs/binder/tests/include_tls_test_utils/binder/RpcTlsTestUtils.h
+++ b/libs/binder/tests/include_tls_test_utils/binder/RpcTlsTestUtils.h
@@ -18,6 +18,7 @@
#include <memory>
#include <mutex>
+#include <vector>
#include <binder/RpcAuth.h>
#include <binder/RpcCertificateFormat.h>
diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
index 57d496d..e5d32da 100644
--- a/libs/binder/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/Android.bp
@@ -29,7 +29,6 @@
"libcutils",
"libhidlbase",
"liblog",
- "libutils",
],
target: {
@@ -37,12 +36,14 @@
shared_libs: [
"libbinder_ndk",
"libbinder",
+ "libutils",
],
},
host: {
static_libs: [
"libbinder_ndk",
"libbinder",
+ "libutils",
],
},
darwin: {
diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp
index bc2eb23..c010a2e 100644
--- a/libs/ftl/Android.bp
+++ b/libs/ftl/Android.bp
@@ -14,10 +14,11 @@
address: true,
},
srcs: [
- "Flags_test.cpp",
"cast_test.cpp",
"concat_test.cpp",
"enum_test.cpp",
+ "fake_guard_test.cpp",
+ "flags_test.cpp",
"future_test.cpp",
"small_map_test.cpp",
"small_vector_test.cpp",
@@ -29,13 +30,6 @@
"-Werror",
"-Wextra",
"-Wpedantic",
- ],
-
- header_libs: [
- "libbase_headers",
- ],
-
- shared_libs: [
- "libbase",
+ "-Wthread-safety",
],
}
diff --git a/libs/ftl/enum_test.cpp b/libs/ftl/enum_test.cpp
index d8ce7a5..5592a01 100644
--- a/libs/ftl/enum_test.cpp
+++ b/libs/ftl/enum_test.cpp
@@ -143,6 +143,16 @@
EXPECT_EQ(ftl::flag_string(Flags::kNone), "0b0");
EXPECT_EQ(ftl::flag_string(Flags::kMask), "0b10010010");
EXPECT_EQ(ftl::flag_string(Flags::kAll), "0b11111111");
+
+ enum class Flags64 : std::uint64_t {
+ kFlag0 = 0b1ull,
+ kFlag63 = 0x8000'0000'0000'0000ull,
+ kMask = kFlag0 | kFlag63
+ };
+
+ EXPECT_EQ(ftl::flag_string(Flags64::kFlag0), "kFlag0");
+ EXPECT_EQ(ftl::flag_string(Flags64::kFlag63), "kFlag63");
+ EXPECT_EQ(ftl::flag_string(Flags64::kMask), "0x8000000000000001");
}
{
EXPECT_EQ(ftl::enum_string(Planet::kEarth), "kEarth");
diff --git a/libs/ftl/fake_guard_test.cpp b/libs/ftl/fake_guard_test.cpp
new file mode 100644
index 0000000..9d36e69
--- /dev/null
+++ b/libs/ftl/fake_guard_test.cpp
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+#include <ftl/fake_guard.h>
+#include <gtest/gtest.h>
+
+#include <functional>
+#include <mutex>
+
+namespace android::test {
+
+// Keep in sync with example usage in header file.
+TEST(FakeGuard, Example) {
+ struct {
+ std::mutex mutex;
+ int x FTL_ATTRIBUTE(guarded_by(mutex)) = -1;
+
+ int f() {
+ {
+ ftl::FakeGuard guard(mutex);
+ x = 0;
+ }
+
+ return FTL_FAKE_GUARD(mutex, x + 1);
+ }
+
+ std::function<int()> g() const {
+ return [this]() FTL_FAKE_GUARD(mutex) { return x; };
+ }
+ } s;
+
+ EXPECT_EQ(s.f(), 1);
+ EXPECT_EQ(s.g()(), 0);
+}
+
+} // namespace android::test
diff --git a/libs/ftl/Flags_test.cpp b/libs/ftl/flags_test.cpp
similarity index 98%
rename from libs/ftl/Flags_test.cpp
rename to libs/ftl/flags_test.cpp
index d241fa2..eea052b 100644
--- a/libs/ftl/Flags_test.cpp
+++ b/libs/ftl/flags_test.cpp
@@ -14,14 +14,15 @@
* limitations under the License.
*/
+#include <ftl/flags.h>
#include <gtest/gtest.h>
-#include <ftl/Flags.h>
#include <type_traits>
namespace android::test {
-using namespace android::flag_operators;
+using ftl::Flags;
+using namespace ftl::flag_operators;
enum class TestFlags : uint8_t { ONE = 0x1, TWO = 0x2, THREE = 0x4 };
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 5532c6e..24d39fe 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -226,101 +226,6 @@
return result;
}
- sp<IBinder> createDisplay(const String8& displayName, bool secure) override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- status_t status = data.writeString8(displayName);
- if (status) {
- return nullptr;
- }
- status = data.writeBool(secure);
- if (status) {
- return nullptr;
- }
-
- status = remote()->transact(BnSurfaceComposer::CREATE_DISPLAY, data, &reply);
- if (status) {
- return nullptr;
- }
- sp<IBinder> display;
- status = reply.readNullableStrongBinder(&display);
- if (status) {
- return nullptr;
- }
- return display;
- }
-
- void destroyDisplay(const sp<IBinder>& display) override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeStrongBinder(display);
- remote()->transact(BnSurfaceComposer::DESTROY_DISPLAY, data, &reply);
- }
-
- std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (remote()->transact(BnSurfaceComposer::GET_PHYSICAL_DISPLAY_IDS, data, &reply) ==
- NO_ERROR) {
- std::vector<uint64_t> rawIds;
- if (reply.readUint64Vector(&rawIds) == NO_ERROR) {
- std::vector<PhysicalDisplayId> displayIds;
- displayIds.reserve(rawIds.size());
-
- for (const uint64_t rawId : rawIds) {
- if (const auto id = DisplayId::fromValue<PhysicalDisplayId>(rawId)) {
- displayIds.push_back(*id);
- }
- }
- return displayIds;
- }
- }
-
- return {};
- }
-
- status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId* displayId) const override {
- Parcel data, reply;
- SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
- SAFE_PARCEL(remote()->transact, BnSurfaceComposer::GET_PRIMARY_PHYSICAL_DISPLAY_ID, data,
- &reply);
- uint64_t rawId;
- SAFE_PARCEL(reply.readUint64, &rawId);
- if (const auto id = DisplayId::fromValue<PhysicalDisplayId>(rawId)) {
- *displayId = *id;
- return NO_ERROR;
- }
- return NAME_NOT_FOUND;
- }
-
- sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeUint64(displayId.value);
- remote()->transact(BnSurfaceComposer::GET_PHYSICAL_DISPLAY_TOKEN, data, &reply);
- return reply.readStrongBinder();
- }
-
- void setPowerMode(const sp<IBinder>& display, int mode) override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeStrongBinder(display);
- data.writeInt32(mode);
- remote()->transact(BnSurfaceComposer::SET_POWER_MODE, data, &reply);
- }
-
- status_t getDisplayState(const sp<IBinder>& display, ui::DisplayState* state) override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeStrongBinder(display);
- remote()->transact(BnSurfaceComposer::GET_DISPLAY_STATE, data, &reply);
- const status_t result = reply.readInt32();
- if (result == NO_ERROR) {
- memcpy(state, reply.readInplace(sizeof(ui::DisplayState)), sizeof(ui::DisplayState));
- }
- return result;
- }
-
status_t getStaticDisplayInfo(const sp<IBinder>& display,
ui::StaticDisplayInfo* info) override {
Parcel data, reply;
@@ -343,20 +248,6 @@
return reply.read(*info);
}
- status_t getDisplayStats(const sp<IBinder>& display, DisplayStatInfo* stats) override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeStrongBinder(display);
- remote()->transact(BnSurfaceComposer::GET_DISPLAY_STATS, data, &reply);
- status_t result = reply.readInt32();
- if (result == NO_ERROR) {
- memcpy(stats,
- reply.readInplace(sizeof(DisplayStatInfo)),
- sizeof(DisplayStatInfo));
- }
- return result;
- }
-
status_t getDisplayNativePrimaries(const sp<IBinder>& display,
ui::DisplayPrimaries& primaries) override {
Parcel data, reply;
@@ -408,29 +299,6 @@
return static_cast<status_t>(reply.readInt32());
}
- // TODO(b/213909104) : Add unit tests to verify surface flinger boot time APIs
- status_t getBootDisplayModeSupport(bool* outSupport) const override {
- Parcel data, reply;
- status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (error != NO_ERROR) {
- ALOGE("getBootDisplayModeSupport: failed to write interface token: %d", error);
- return error;
- }
- error = remote()->transact(BnSurfaceComposer::GET_BOOT_DISPLAY_MODE_SUPPORT, data, &reply);
- if (error != NO_ERROR) {
- ALOGE("getBootDisplayModeSupport: failed to transact: %d", error);
- return error;
- }
- bool support;
- error = reply.readBool(&support);
- if (error != NO_ERROR) {
- ALOGE("getBootDisplayModeSupport: failed to read support: %d", error);
- return error;
- }
- *outSupport = support;
- return NO_ERROR;
- }
-
status_t setBootDisplayMode(const sp<IBinder>& display,
ui::DisplayModeId displayModeId) override {
Parcel data, reply;
@@ -456,73 +324,6 @@
return result;
}
- status_t clearBootDisplayMode(const sp<IBinder>& display) override {
- Parcel data, reply;
- status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (result != NO_ERROR) {
- ALOGE("clearBootDisplayMode failed to writeInterfaceToken: %d", result);
- return result;
- }
- result = data.writeStrongBinder(display);
- if (result != NO_ERROR) {
- ALOGE("clearBootDisplayMode failed to writeStrongBinder: %d", result);
- return result;
- }
- result = remote()->transact(BnSurfaceComposer::CLEAR_BOOT_DISPLAY_MODE, data, &reply);
- if (result != NO_ERROR) {
- ALOGE("clearBootDisplayMode failed to transact: %d", result);
- }
- return result;
- }
-
- void setAutoLowLatencyMode(const sp<IBinder>& display, bool on) override {
- Parcel data, reply;
- status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (result != NO_ERROR) {
- ALOGE("setAutoLowLatencyMode failed to writeInterfaceToken: %d", result);
- return;
- }
-
- result = data.writeStrongBinder(display);
- if (result != NO_ERROR) {
- ALOGE("setAutoLowLatencyMode failed to writeStrongBinder: %d", result);
- return;
- }
- result = data.writeBool(on);
- if (result != NO_ERROR) {
- ALOGE("setAutoLowLatencyMode failed to writeBool: %d", result);
- return;
- }
- result = remote()->transact(BnSurfaceComposer::SET_AUTO_LOW_LATENCY_MODE, data, &reply);
- if (result != NO_ERROR) {
- ALOGE("setAutoLowLatencyMode failed to transact: %d", result);
- return;
- }
- }
-
- void setGameContentType(const sp<IBinder>& display, bool on) override {
- Parcel data, reply;
- status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (result != NO_ERROR) {
- ALOGE("setGameContentType failed to writeInterfaceToken: %d", result);
- return;
- }
- result = data.writeStrongBinder(display);
- if (result != NO_ERROR) {
- ALOGE("setGameContentType failed to writeStrongBinder: %d", result);
- return;
- }
- result = data.writeBool(on);
- if (result != NO_ERROR) {
- ALOGE("setGameContentType failed to writeBool: %d", result);
- return;
- }
- result = remote()->transact(BnSurfaceComposer::SET_GAME_CONTENT_TYPE, data, &reply);
- if (result != NO_ERROR) {
- ALOGE("setGameContentType failed to transact: %d", result);
- }
- }
-
status_t clearAnimationFrameStats() override {
Parcel data, reply;
status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -797,26 +598,6 @@
return error;
}
- status_t isWideColorDisplay(const sp<IBinder>& token,
- bool* outIsWideColorDisplay) const override {
- Parcel data, reply;
- status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (error != NO_ERROR) {
- return error;
- }
- error = data.writeStrongBinder(token);
- if (error != NO_ERROR) {
- return error;
- }
-
- error = remote()->transact(BnSurfaceComposer::IS_WIDE_COLOR_DISPLAY, data, &reply);
- if (error != NO_ERROR) {
- return error;
- }
- error = reply.readBool(outIsWideColorDisplay);
- return error;
- }
-
status_t addRegionSamplingListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
const sp<IRegionSamplingListener>& listener) override {
Parcel data, reply;
@@ -1049,109 +830,6 @@
return reply.readInt32();
}
- status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
- bool* outSupport) const override {
- Parcel data, reply;
- status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (error != NO_ERROR) {
- ALOGE("getDisplayBrightnessSupport: failed to write interface token: %d", error);
- return error;
- }
- error = data.writeStrongBinder(displayToken);
- if (error != NO_ERROR) {
- ALOGE("getDisplayBrightnessSupport: failed to write display token: %d", error);
- return error;
- }
- error = remote()->transact(BnSurfaceComposer::GET_DISPLAY_BRIGHTNESS_SUPPORT, data, &reply);
- if (error != NO_ERROR) {
- ALOGE("getDisplayBrightnessSupport: failed to transact: %d", error);
- return error;
- }
- bool support;
- error = reply.readBool(&support);
- if (error != NO_ERROR) {
- ALOGE("getDisplayBrightnessSupport: failed to read support: %d", error);
- return error;
- }
- *outSupport = support;
- return NO_ERROR;
- }
-
- status_t setDisplayBrightness(const sp<IBinder>& displayToken,
- const gui::DisplayBrightness& brightness) override {
- Parcel data, reply;
- status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (error != NO_ERROR) {
- ALOGE("setDisplayBrightness: failed to write interface token: %d", error);
- return error;
- }
- error = data.writeStrongBinder(displayToken);
- if (error != NO_ERROR) {
- ALOGE("setDisplayBrightness: failed to write display token: %d", error);
- return error;
- }
- error = data.writeParcelable(brightness);
- if (error != NO_ERROR) {
- ALOGE("setDisplayBrightness: failed to write brightness: %d", error);
- return error;
- }
- error = remote()->transact(BnSurfaceComposer::SET_DISPLAY_BRIGHTNESS, data, &reply);
- if (error != NO_ERROR) {
- ALOGE("setDisplayBrightness: failed to transact: %d", error);
- return error;
- }
- return NO_ERROR;
- }
-
- status_t addHdrLayerInfoListener(const sp<IBinder>& displayToken,
- const sp<gui::IHdrLayerInfoListener>& listener) override {
- Parcel data, reply;
- SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
- SAFE_PARCEL(data.writeStrongBinder, displayToken);
- SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener));
- const status_t error =
- remote()->transact(BnSurfaceComposer::ADD_HDR_LAYER_INFO_LISTENER, data, &reply);
- if (error != OK) {
- ALOGE("addHdrLayerInfoListener: Failed to transact; error = %d", error);
- }
- return error;
- }
-
- status_t removeHdrLayerInfoListener(const sp<IBinder>& displayToken,
- const sp<gui::IHdrLayerInfoListener>& listener) override {
- Parcel data, reply;
- SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
- SAFE_PARCEL(data.writeStrongBinder, displayToken);
- SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener));
- const status_t error =
- remote()->transact(BnSurfaceComposer::REMOVE_HDR_LAYER_INFO_LISTENER, data, &reply);
- if (error != OK) {
- ALOGE("removeHdrLayerInfoListener: Failed to transact; error = %d", error);
- }
- return error;
- }
-
- status_t notifyPowerBoost(int32_t boostId) override {
- Parcel data, reply;
- status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (error != NO_ERROR) {
- ALOGE("notifyPowerBoost: failed to write interface token: %d", error);
- return error;
- }
- error = data.writeInt32(boostId);
- if (error != NO_ERROR) {
- ALOGE("notifyPowerBoost: failed to write boostId: %d", error);
- return error;
- }
- error = remote()->transact(BnSurfaceComposer::NOTIFY_POWER_BOOST, data, &reply,
- IBinder::FLAG_ONEWAY);
- if (error != NO_ERROR) {
- ALOGE("notifyPowerBoost: failed to transact: %d", error);
- return error;
- }
- return NO_ERROR;
- }
-
status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
float lightPosY, float lightPosZ, float lightRadius) override {
Parcel data, reply;
@@ -1467,41 +1145,6 @@
reply->writeStrongBinder(IInterface::asBinder(connection));
return NO_ERROR;
}
- case CREATE_DISPLAY: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- String8 displayName;
- SAFE_PARCEL(data.readString8, &displayName);
- bool secure = false;
- SAFE_PARCEL(data.readBool, &secure);
- sp<IBinder> display = createDisplay(displayName, secure);
- SAFE_PARCEL(reply->writeStrongBinder, display);
- return NO_ERROR;
- }
- case DESTROY_DISPLAY: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = data.readStrongBinder();
- destroyDisplay(display);
- return NO_ERROR;
- }
- case GET_PHYSICAL_DISPLAY_TOKEN: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- const auto id = DisplayId::fromValue<PhysicalDisplayId>(data.readUint64());
- if (!id) return BAD_VALUE;
- reply->writeStrongBinder(getPhysicalDisplayToken(*id));
- return NO_ERROR;
- }
- case GET_DISPLAY_STATE: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- ui::DisplayState state;
- const sp<IBinder> display = data.readStrongBinder();
- const status_t result = getDisplayState(display, &state);
- reply->writeInt32(result);
- if (result == NO_ERROR) {
- memcpy(reply->writeInplace(sizeof(ui::DisplayState)), &state,
- sizeof(ui::DisplayState));
- }
- return NO_ERROR;
- }
case GET_STATIC_DISPLAY_INFO: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
ui::StaticDisplayInfo info;
@@ -1522,18 +1165,6 @@
SAFE_PARCEL(reply->write, info);
return NO_ERROR;
}
- case GET_DISPLAY_STATS: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- DisplayStatInfo stats;
- sp<IBinder> display = data.readStrongBinder();
- status_t result = getDisplayStats(display, &stats);
- reply->writeInt32(result);
- if (result == NO_ERROR) {
- memcpy(reply->writeInplace(sizeof(DisplayStatInfo)),
- &stats, sizeof(DisplayStatInfo));
- }
- return NO_ERROR;
- }
case GET_DISPLAY_NATIVE_PRIMARIES: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
ui::DisplayPrimaries primaries;
@@ -1573,15 +1204,6 @@
result = reply->writeInt32(result);
return result;
}
- case GET_BOOT_DISPLAY_MODE_SUPPORT: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- bool support = false;
- status_t result = getBootDisplayModeSupport(&support);
- if (result == NO_ERROR) {
- reply->writeBool(support);
- }
- return result;
- }
case SET_BOOT_DISPLAY_MODE: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> display = nullptr;
@@ -1598,50 +1220,6 @@
}
return setBootDisplayMode(display, displayModeId);
}
- case CLEAR_BOOT_DISPLAY_MODE: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = nullptr;
- status_t result = data.readStrongBinder(&display);
- if (result != NO_ERROR) {
- ALOGE("clearBootDisplayMode failed to readStrongBinder: %d", result);
- return result;
- }
- return clearBootDisplayMode(display);
- }
- case SET_AUTO_LOW_LATENCY_MODE: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = nullptr;
- status_t result = data.readStrongBinder(&display);
- if (result != NO_ERROR) {
- ALOGE("setAutoLowLatencyMode failed to readStrongBinder: %d", result);
- return result;
- }
- bool setAllm = false;
- result = data.readBool(&setAllm);
- if (result != NO_ERROR) {
- ALOGE("setAutoLowLatencyMode failed to readBool: %d", result);
- return result;
- }
- setAutoLowLatencyMode(display, setAllm);
- return result;
- }
- case SET_GAME_CONTENT_TYPE: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = nullptr;
- status_t result = data.readStrongBinder(&display);
- if (result != NO_ERROR) {
- ALOGE("setGameContentType failed to readStrongBinder: %d", result);
- return result;
- }
- bool setGameContentTypeOn = false;
- result = data.readBool(&setGameContentTypeOn);
- if (result != NO_ERROR) {
- ALOGE("setGameContentType failed to readBool: %d", result);
- return result;
- }
- setGameContentType(display, setGameContentTypeOn);
- return result;
- }
case CLEAR_ANIMATION_FRAME_STATS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
status_t result = clearAnimationFrameStats();
@@ -1656,13 +1234,6 @@
reply->writeInt32(result);
return NO_ERROR;
}
- case SET_POWER_MODE: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = data.readStrongBinder();
- int32_t mode = data.readInt32();
- setPowerMode(display, mode);
- return NO_ERROR;
- }
case ENABLE_VSYNC_INJECTIONS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
bool enable = false;
@@ -1812,38 +1383,6 @@
}
return error;
}
- case IS_WIDE_COLOR_DISPLAY: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = nullptr;
- status_t error = data.readStrongBinder(&display);
- if (error != NO_ERROR) {
- return error;
- }
- bool result;
- error = isWideColorDisplay(display, &result);
- if (error == NO_ERROR) {
- reply->writeBool(result);
- }
- return error;
- }
- case GET_PHYSICAL_DISPLAY_IDS: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- std::vector<PhysicalDisplayId> ids = getPhysicalDisplayIds();
- std::vector<uint64_t> rawIds(ids.size());
- std::transform(ids.begin(), ids.end(), rawIds.begin(),
- [](PhysicalDisplayId id) { return id.value; });
- return reply->writeUint64Vector(rawIds);
- }
- case GET_PRIMARY_PHYSICAL_DISPLAY_ID: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- PhysicalDisplayId id;
- status_t result = getPrimaryPhysicalDisplayId(&id);
- if (result != NO_ERROR) {
- ALOGE("getPrimaryPhysicalDisplayId: Failed to get id");
- return result;
- }
- return reply->writeUint64(id.value);
- }
case ADD_REGION_SAMPLING_LISTENER: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
Rect samplingArea;
@@ -2041,77 +1580,6 @@
reply->writeInt32(result);
return result;
}
- case GET_DISPLAY_BRIGHTNESS_SUPPORT: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> displayToken;
- status_t error = data.readNullableStrongBinder(&displayToken);
- if (error != NO_ERROR) {
- ALOGE("getDisplayBrightnessSupport: failed to read display token: %d", error);
- return error;
- }
- bool support = false;
- error = getDisplayBrightnessSupport(displayToken, &support);
- reply->writeBool(support);
- return error;
- }
- case SET_DISPLAY_BRIGHTNESS: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> displayToken;
- status_t error = data.readNullableStrongBinder(&displayToken);
- if (error != NO_ERROR) {
- ALOGE("setDisplayBrightness: failed to read display token: %d", error);
- return error;
- }
- gui::DisplayBrightness brightness;
- error = data.readParcelable(&brightness);
- if (error != NO_ERROR) {
- ALOGE("setDisplayBrightness: failed to read brightness: %d", error);
- return error;
- }
- return setDisplayBrightness(displayToken, brightness);
- }
- case ADD_HDR_LAYER_INFO_LISTENER: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> displayToken;
- status_t error = data.readNullableStrongBinder(&displayToken);
- if (error != NO_ERROR) {
- ALOGE("addHdrLayerInfoListener: Failed to read display token");
- return error;
- }
- sp<gui::IHdrLayerInfoListener> listener;
- error = data.readNullableStrongBinder(&listener);
- if (error != NO_ERROR) {
- ALOGE("addHdrLayerInfoListener: Failed to read listener");
- return error;
- }
- return addHdrLayerInfoListener(displayToken, listener);
- }
- case REMOVE_HDR_LAYER_INFO_LISTENER: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> displayToken;
- status_t error = data.readNullableStrongBinder(&displayToken);
- if (error != NO_ERROR) {
- ALOGE("removeHdrLayerInfoListener: Failed to read display token");
- return error;
- }
- sp<gui::IHdrLayerInfoListener> listener;
- error = data.readNullableStrongBinder(&listener);
- if (error != NO_ERROR) {
- ALOGE("removeHdrLayerInfoListener: Failed to read listener");
- return error;
- }
- return removeHdrLayerInfoListener(displayToken, listener);
- }
- case NOTIFY_POWER_BOOST: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- int32_t boostId;
- status_t error = data.readInt32(&boostId);
- if (error != NO_ERROR) {
- ALOGE("notifyPowerBoost: failed to read boostId: %d", error);
- return error;
- }
- return notifyPowerBoost(boostId);
- }
case SET_GLOBAL_SHADOW_SETTINGS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 34db5b1..502031c 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -16,8 +16,8 @@
#define LOG_TAG "LayerState"
-#include <apex/window.h>
-#include <inttypes.h>
+#include <cinttypes>
+#include <cmath>
#include <android/native_window.h>
#include <binder/Parcel.h>
@@ -25,10 +25,9 @@
#include <gui/ISurfaceComposerClient.h>
#include <gui/LayerState.h>
#include <private/gui/ParcelUtils.h>
+#include <system/window.h>
#include <utils/Errors.h>
-#include <cmath>
-
namespace android {
using gui::FocusRequest;
@@ -134,6 +133,7 @@
SAFE_PARCEL(output.writeByte, changeFrameRateStrategy);
SAFE_PARCEL(output.writeUint32, fixedTransformHint);
SAFE_PARCEL(output.writeBool, autoRefresh);
+ SAFE_PARCEL(output.writeBool, dimmingEnabled);
SAFE_PARCEL(output.writeUint32, blurRegions.size());
for (auto region : blurRegions) {
@@ -243,6 +243,7 @@
SAFE_PARCEL(input.readUint32, &tmpUint32);
fixedTransformHint = static_cast<ui::Transform::RotationFlags>(tmpUint32);
SAFE_PARCEL(input.readBool, &autoRefresh);
+ SAFE_PARCEL(input.readBool, &dimmingEnabled);
uint32_t numRegions = 0;
SAFE_PARCEL(input.readUint32, &numRegions);
@@ -598,6 +599,10 @@
what |= eColorSpaceAgnosticChanged;
colorSpaceAgnostic = other.colorSpaceAgnostic;
}
+ if (other.what & eDimmingEnabledChanged) {
+ what |= eDimmingEnabledChanged;
+ dimmingEnabled = other.dimmingEnabled;
+ }
if ((other.what & what) != other.what) {
ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
"other.what=0x%" PRIX64 " what=0x%" PRIX64 " unmerged flags=0x%" PRIX64,
@@ -673,7 +678,9 @@
if (compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT &&
compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE &&
- (!privileged || compatibility != ANATIVEWINDOW_FRAME_RATE_EXACT)) {
+ (!privileged ||
+ (compatibility != ANATIVEWINDOW_FRAME_RATE_EXACT &&
+ compatibility != ANATIVEWINDOW_FRAME_RATE_NO_VOTE))) {
ALOGE("%s failed - invalid compatibility value %d privileged: %s", functionName,
compatibility, privileged ? "yes" : "no");
return false;
@@ -815,7 +822,7 @@
status_t BufferData::readFromParcel(const Parcel* input) {
int32_t tmpInt32;
SAFE_PARCEL(input->readInt32, &tmpInt32);
- flags = Flags<BufferDataChange>(tmpInt32);
+ flags = ftl::Flags<BufferDataChange>(tmpInt32);
bool tmpBool = false;
SAFE_PARCEL(input->readBool, &tmpBool);
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 20c4146..54b6d6a 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -27,13 +27,13 @@
#include <inttypes.h>
+#include <android/gui/DisplayStatInfo.h>
#include <android/native_window.h>
#include <utils/Log.h>
#include <utils/Trace.h>
#include <utils/NativeHandle.h>
-#include <ui/DisplayStatInfo.h>
#include <ui/DynamicDisplayInfo.h>
#include <ui/Fence.h>
#include <ui/GraphicBuffer.h>
@@ -45,6 +45,7 @@
#include <gui/ISurfaceComposer.h>
#include <gui/LayerState.h>
#include <private/gui/ComposerService.h>
+#include <private/gui/ComposerServiceAIDL.h>
namespace android {
@@ -125,6 +126,10 @@
return ComposerService::getComposerService();
}
+sp<gui::ISurfaceComposer> Surface::composerServiceAIDL() const {
+ return ComposerServiceAIDL::getComposerService();
+}
+
nsecs_t Surface::now() const {
return systemTime();
}
@@ -174,10 +179,10 @@
status_t Surface::getDisplayRefreshCycleDuration(nsecs_t* outRefreshDuration) {
ATRACE_CALL();
- DisplayStatInfo stats;
- status_t result = composerService()->getDisplayStats(nullptr, &stats);
- if (result != NO_ERROR) {
- return result;
+ gui::DisplayStatInfo stats;
+ binder::Status status = composerServiceAIDL()->getDisplayStats(nullptr, &stats);
+ if (!status.isOk()) {
+ return status.transactionError();
}
*outRefreshDuration = stats.vsyncPeriod;
@@ -343,20 +348,20 @@
status_t Surface::getWideColorSupport(bool* supported) {
ATRACE_CALL();
- const sp<IBinder> display = composerService()->getInternalDisplayToken();
+ const sp<IBinder> display = ComposerServiceAIDL::getInstance().getInternalDisplayToken();
if (display == nullptr) {
return NAME_NOT_FOUND;
}
*supported = false;
- status_t error = composerService()->isWideColorDisplay(display, supported);
- return error;
+ binder::Status status = composerServiceAIDL()->isWideColorDisplay(display, supported);
+ return status.transactionError();
}
status_t Surface::getHdrSupport(bool* supported) {
ATRACE_CALL();
- const sp<IBinder> display = composerService()->getInternalDisplayToken();
+ const sp<IBinder> display = ComposerServiceAIDL::getInstance().getInternalDisplayToken();
if (display == nullptr) {
return NAME_NOT_FOUND;
}
@@ -1096,6 +1101,17 @@
*out = input;
}
+void Surface::applyGrallocMetadataLocked(
+ android_native_buffer_t* buffer,
+ const IGraphicBufferProducer::QueueBufferInput& queueBufferInput) {
+ ATRACE_CALL();
+ auto& mapper = GraphicBufferMapper::get();
+ mapper.setDataspace(buffer->handle, static_cast<ui::Dataspace>(queueBufferInput.dataSpace));
+ mapper.setSmpte2086(buffer->handle, queueBufferInput.getHdrMetadata().getSmpte2086());
+ mapper.setCta861_3(buffer->handle, queueBufferInput.getHdrMetadata().getCta8613());
+ mapper.setSmpte2094_40(buffer->handle, queueBufferInput.getHdrMetadata().getHdr10Plus());
+}
+
void Surface::onBufferQueuedLocked(int slot, sp<Fence> fence,
const IGraphicBufferProducer::QueueBufferOutput& output) {
mDequeuedSlots.erase(slot);
@@ -1166,9 +1182,11 @@
IGraphicBufferProducer::QueueBufferOutput output;
IGraphicBufferProducer::QueueBufferInput input;
getQueueBufferInputLocked(buffer, fenceFd, mTimestamp, &input);
+ applyGrallocMetadataLocked(buffer, input);
sp<Fence> fence = input.fence;
nsecs_t now = systemTime();
+
status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output);
mLastQueueDuration = systemTime() - now;
if (err != OK) {
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 52a22a7..7a63af0 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <sys/types.h>
+#include <android/gui/DisplayState.h>
#include <android/gui/IWindowInfosListener.h>
#include <utils/Errors.h>
#include <utils/Log.h>
@@ -43,6 +44,7 @@
#include <gui/WindowInfo.h>
#include <private/gui/ParcelUtils.h>
#include <ui/DisplayMode.h>
+#include <ui/DisplayState.h>
#include <ui/DynamicDisplayInfo.h>
#include <private/gui/ComposerService.h>
@@ -206,12 +208,14 @@
}
sp<TransactionCompletedListener> TransactionCompletedListener::sInstance = nullptr;
+static std::mutex sListenerInstanceMutex;
void TransactionCompletedListener::setInstance(const sp<TransactionCompletedListener>& listener) {
sInstance = listener;
}
sp<TransactionCompletedListener> TransactionCompletedListener::getInstance() {
+ std::lock_guard<std::mutex> lock(sListenerInstanceMutex);
if (sInstance == nullptr) {
sInstance = new TransactionCompletedListener;
}
@@ -1022,32 +1026,59 @@
// ---------------------------------------------------------------------------
sp<IBinder> SurfaceComposerClient::createDisplay(const String8& displayName, bool secure) {
- return ComposerService::getComposerService()->createDisplay(displayName,
- secure);
+ sp<IBinder> display = nullptr;
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->createDisplay(std::string(
+ displayName.string()),
+ secure, &display);
+ return status.isOk() ? display : nullptr;
}
void SurfaceComposerClient::destroyDisplay(const sp<IBinder>& display) {
- return ComposerService::getComposerService()->destroyDisplay(display);
+ ComposerServiceAIDL::getComposerService()->destroyDisplay(display);
}
std::vector<PhysicalDisplayId> SurfaceComposerClient::getPhysicalDisplayIds() {
- return ComposerService::getComposerService()->getPhysicalDisplayIds();
+ std::vector<int64_t> displayIds;
+ std::vector<PhysicalDisplayId> physicalDisplayIds;
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->getPhysicalDisplayIds(&displayIds);
+ if (status.isOk()) {
+ physicalDisplayIds.reserve(displayIds.size());
+ for (auto item : displayIds) {
+ auto id = DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(item));
+ physicalDisplayIds.push_back(*id);
+ }
+ }
+ return physicalDisplayIds;
}
status_t SurfaceComposerClient::getPrimaryPhysicalDisplayId(PhysicalDisplayId* id) {
- return ComposerService::getComposerService()->getPrimaryPhysicalDisplayId(id);
+ int64_t displayId;
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->getPrimaryPhysicalDisplayId(&displayId);
+ if (status.isOk()) {
+ *id = *DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(displayId));
+ }
+ return status.transactionError();
}
std::optional<PhysicalDisplayId> SurfaceComposerClient::getInternalDisplayId() {
- return ComposerService::getComposerService()->getInternalDisplayId();
+ ComposerServiceAIDL& instance = ComposerServiceAIDL::getInstance();
+ return instance.getInternalDisplayId();
}
sp<IBinder> SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId displayId) {
- return ComposerService::getComposerService()->getPhysicalDisplayToken(displayId);
+ sp<IBinder> display = nullptr;
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->getPhysicalDisplayToken(displayId.value,
+ &display);
+ return status.isOk() ? display : nullptr;
}
sp<IBinder> SurfaceComposerClient::getInternalDisplayToken() {
- return ComposerService::getComposerService()->getInternalDisplayToken();
+ ComposerServiceAIDL& instance = ComposerServiceAIDL::getInstance();
+ return instance.getInternalDisplayToken();
}
void SurfaceComposerClient::Transaction::setAnimationTransaction() {
@@ -1195,6 +1226,20 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDimmingEnabled(
+ const sp<SurfaceControl>& sc, bool dimmingEnabled) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+ s->what |= layer_state_t::eDimmingEnabledChanged;
+ s->dimmingEnabled = dimmingEnabled;
+
+ registerSurfaceControlForCallback(sc);
+ return *this;
+}
+
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAlpha(
const sp<SurfaceControl>& sc, float alpha) {
layer_state_t* s = getLayerState(sc);
@@ -2086,7 +2131,16 @@
status_t SurfaceComposerClient::getDisplayState(const sp<IBinder>& display,
ui::DisplayState* state) {
- return ComposerService::getComposerService()->getDisplayState(display, state);
+ gui::DisplayState ds;
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->getDisplayState(display, &ds);
+ if (status.isOk()) {
+ state->layerStack = ui::LayerStack::fromValue(ds.layerStack);
+ state->orientation = static_cast<ui::Rotation>(ds.orientation);
+ state->layerStackSpaceRect =
+ ui::Size(ds.layerStackSpaceRect.width, ds.layerStackSpaceRect.height);
+ }
+ return status.transactionError();
}
status_t SurfaceComposerClient::getStaticDisplayInfo(const sp<IBinder>& display,
@@ -2150,7 +2204,9 @@
}
status_t SurfaceComposerClient::getBootDisplayModeSupport(bool* support) {
- return ComposerService::getComposerService()->getBootDisplayModeSupport(support);
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->getBootDisplayModeSupport(support);
+ return status.transactionError();
}
status_t SurfaceComposerClient::setBootDisplayMode(const sp<IBinder>& display,
@@ -2159,7 +2215,9 @@
}
status_t SurfaceComposerClient::clearBootDisplayMode(const sp<IBinder>& display) {
- return ComposerService::getComposerService()->clearBootDisplayMode(display);
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->clearBootDisplayMode(display);
+ return status.transactionError();
}
status_t SurfaceComposerClient::setOverrideFrameRate(uid_t uid, float frameRate) {
@@ -2167,16 +2225,16 @@
}
void SurfaceComposerClient::setAutoLowLatencyMode(const sp<IBinder>& display, bool on) {
- ComposerService::getComposerService()->setAutoLowLatencyMode(display, on);
+ ComposerServiceAIDL::getComposerService()->setAutoLowLatencyMode(display, on);
}
void SurfaceComposerClient::setGameContentType(const sp<IBinder>& display, bool on) {
- ComposerService::getComposerService()->setGameContentType(display, on);
+ ComposerServiceAIDL::getComposerService()->setGameContentType(display, on);
}
void SurfaceComposerClient::setDisplayPowerMode(const sp<IBinder>& token,
int mode) {
- ComposerService::getComposerService()->setPowerMode(token, mode);
+ ComposerServiceAIDL::getComposerService()->setPowerMode(token, mode);
}
status_t SurfaceComposerClient::getCompositionPreference(
@@ -2237,8 +2295,10 @@
status_t SurfaceComposerClient::isWideColorDisplay(const sp<IBinder>& display,
bool* outIsWideColorDisplay) {
- return ComposerService::getComposerService()->isWideColorDisplay(display,
- outIsWideColorDisplay);
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->isWideColorDisplay(display,
+ outIsWideColorDisplay);
+ return status.transactionError();
}
status_t SurfaceComposerClient::addRegionSamplingListener(
@@ -2275,28 +2335,39 @@
bool SurfaceComposerClient::getDisplayBrightnessSupport(const sp<IBinder>& displayToken) {
bool support = false;
- ComposerService::getComposerService()->getDisplayBrightnessSupport(displayToken, &support);
- return support;
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->getDisplayBrightnessSupport(displayToken,
+ &support);
+ return status.isOk() ? support : false;
}
status_t SurfaceComposerClient::setDisplayBrightness(const sp<IBinder>& displayToken,
const gui::DisplayBrightness& brightness) {
- return ComposerService::getComposerService()->setDisplayBrightness(displayToken, brightness);
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->setDisplayBrightness(displayToken,
+ brightness);
+ return status.transactionError();
}
status_t SurfaceComposerClient::addHdrLayerInfoListener(
const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) {
- return ComposerService::getComposerService()->addHdrLayerInfoListener(displayToken, listener);
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->addHdrLayerInfoListener(displayToken,
+ listener);
+ return status.transactionError();
}
status_t SurfaceComposerClient::removeHdrLayerInfoListener(
const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) {
- return ComposerService::getComposerService()->removeHdrLayerInfoListener(displayToken,
- listener);
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->removeHdrLayerInfoListener(displayToken,
+ listener);
+ return status.transactionError();
}
status_t SurfaceComposerClient::notifyPowerBoost(int32_t boostId) {
- return ComposerService::getComposerService()->notifyPowerBoost(boostId);
+ binder::Status status = ComposerServiceAIDL::getComposerService()->notifyPowerBoost(boostId);
+ return status.transactionError();
}
status_t SurfaceComposerClient::setGlobalShadowSettings(const half4& ambientColor,
diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp
index 2312a8c..804ce4f 100644
--- a/libs/gui/WindowInfo.cpp
+++ b/libs/gui/WindowInfo.cpp
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-#include <type_traits>
#define LOG_TAG "WindowInfo"
#define LOG_NDEBUG 0
+#include <type_traits>
+
#include <binder/Parcel.h>
#include <gui/WindowInfo.h>
@@ -25,8 +26,7 @@
namespace android::gui {
-// --- WindowInfo ---
-void WindowInfo::setInputConfig(Flags<InputConfig> config, bool value) {
+void WindowInfo::setInputConfig(ftl::Flags<InputConfig> config, bool value) {
if (value) {
inputConfig |= config;
return;
@@ -182,18 +182,16 @@
return status;
}
- layoutParamsFlags = Flags<Flag>(lpFlags);
+ layoutParamsFlags = ftl::Flags<Flag>(lpFlags);
layoutParamsType = static_cast<Type>(lpType);
transform.set({dsdx, dtdx, tx, dtdy, dsdy, ty, 0, 0, 1});
touchOcclusionMode = static_cast<TouchOcclusionMode>(touchOcclusionModeInt);
- inputConfig = Flags<InputConfig>(inputConfigInt);
+ inputConfig = ftl::Flags<InputConfig>(inputConfigInt);
touchableRegionCropHandle = touchableRegionCropHandleSp;
return OK;
}
-// --- WindowInfoHandle ---
-
WindowInfoHandle::WindowInfoHandle() {}
WindowInfoHandle::~WindowInfoHandle() {}
diff --git a/libs/gui/aidl/android/gui/DisplayStatInfo.aidl b/libs/gui/aidl/android/gui/DisplayStatInfo.aidl
new file mode 100644
index 0000000..68f3942
--- /dev/null
+++ b/libs/gui/aidl/android/gui/DisplayStatInfo.aidl
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+package android.gui;
+
+/** @hide */
+parcelable DisplayStatInfo {
+ long vsyncTime;
+ long vsyncPeriod;
+}
diff --git a/libs/gui/aidl/android/gui/DisplayState.aidl b/libs/gui/aidl/android/gui/DisplayState.aidl
new file mode 100644
index 0000000..9589ab6
--- /dev/null
+++ b/libs/gui/aidl/android/gui/DisplayState.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+package android.gui;
+
+import android.gui.Rotation;
+import android.gui.Size;
+
+/** @hide */
+parcelable DisplayState {
+ int layerStack;
+ Rotation orientation = Rotation.Rotation0;
+ Size layerStackSpaceRect;
+}
diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
index 07921a5..a9977b0 100644
--- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
+++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
@@ -17,11 +17,88 @@
package android.gui;
import android.gui.DisplayCaptureArgs;
+import android.gui.DisplayBrightness;
+import android.gui.DisplayState;
+import android.gui.DisplayStatInfo;
+import android.gui.IHdrLayerInfoListener;
import android.gui.LayerCaptureArgs;
import android.gui.IScreenCaptureListener;
/** @hide */
interface ISurfaceComposer {
+
+ /* create a virtual display
+ * requires ACCESS_SURFACE_FLINGER permission.
+ */
+ @nullable IBinder createDisplay(@utf8InCpp String displayName, boolean secure);
+
+ /* destroy a virtual display
+ * requires ACCESS_SURFACE_FLINGER permission.
+ */
+ void destroyDisplay(IBinder display);
+
+ /* get stable IDs for connected physical displays.
+ */
+ long[] getPhysicalDisplayIds();
+
+ long getPrimaryPhysicalDisplayId();
+
+ /* get token for a physical display given its stable ID obtained via getPhysicalDisplayIds or a
+ * DisplayEventReceiver hotplug event.
+ */
+ @nullable IBinder getPhysicalDisplayToken(long displayId);
+
+ /* set display power mode. depending on the mode, it can either trigger
+ * screen on, off or low power mode and wait for it to complete.
+ * requires ACCESS_SURFACE_FLINGER permission.
+ */
+ void setPowerMode(IBinder display, int mode);
+
+ /* returns display statistics for a given display
+ * intended to be used by the media framework to properly schedule
+ * video frames */
+ DisplayStatInfo getDisplayStats(IBinder display);
+
+ /**
+ * Get transactional state of given display.
+ */
+ DisplayState getDisplayState(IBinder display);
+
+ /**
+ * Clears the user-preferred display mode. The device should now boot in system preferred
+ * display mode.
+ */
+ void clearBootDisplayMode(IBinder display);
+
+ /**
+ * Gets whether boot time display mode operations are supported on the device.
+ *
+ * outSupport
+ * An output parameter for whether boot time display mode operations are supported.
+ *
+ * Returns NO_ERROR upon success. Otherwise,
+ * NAME_NOT_FOUND if the display is invalid, or
+ * BAD_VALUE if the output parameter is invalid.
+ */
+ // TODO(b/213909104) : Add unit tests to verify surface flinger boot time APIs
+ boolean getBootDisplayModeSupport();
+
+ /**
+ * Switches Auto Low Latency Mode on/off on the connected display, if it is
+ * available. This should only be called if the display supports Auto Low
+ * Latency Mode as reported in #getDynamicDisplayInfo.
+ * For more information, see the HDMI 2.1 specification.
+ */
+ void setAutoLowLatencyMode(IBinder display, boolean on);
+
+ /**
+ * This will start sending infoframes to the connected display with
+ * ContentType=Game (if on=true). This should only be called if the display
+ * Game Content Type as reported in #getDynamicDisplayInfo.
+ * For more information, see the HDMI 1.4 specification.
+ */
+ void setGameContentType(IBinder display, boolean on);
+
/**
* Capture the specified screen. This requires READ_FRAME_BUFFER
* permission. This function will fail if there is a secure window on
@@ -39,4 +116,67 @@
* is a secure window on screen
*/
void captureLayers(in LayerCaptureArgs args, IScreenCaptureListener listener);
+
+ /*
+ * Queries whether the given display is a wide color display.
+ * Requires the ACCESS_SURFACE_FLINGER permission.
+ */
+ boolean isWideColorDisplay(IBinder token);
+
+ /*
+ * Gets whether brightness operations are supported on a display.
+ *
+ * displayToken
+ * The token of the display.
+ * outSupport
+ * An output parameter for whether brightness operations are supported.
+ *
+ * Returns NO_ERROR upon success. Otherwise,
+ * NAME_NOT_FOUND if the display is invalid, or
+ * BAD_VALUE if the output parameter is invalid.
+ */
+ boolean getDisplayBrightnessSupport(IBinder displayToken);
+
+ /*
+ * Sets the brightness of a display.
+ *
+ * displayToken
+ * The token of the display whose brightness is set.
+ * brightness
+ * The DisplayBrightness info to set on the desired display.
+ *
+ * Returns NO_ERROR upon success. Otherwise,
+ * NAME_NOT_FOUND if the display is invalid, or
+ * BAD_VALUE if the brightness is invalid, or
+ * INVALID_OPERATION if brightness operations are not supported.
+ */
+ void setDisplayBrightness(IBinder displayToken, in DisplayBrightness brightness);
+
+ /*
+ * Adds a listener that receives HDR layer information. This is used in combination
+ * with setDisplayBrightness to adjust the display brightness depending on factors such
+ * as whether or not HDR is in use.
+ *
+ * Returns NO_ERROR upon success or NAME_NOT_FOUND if the display is invalid.
+ */
+ void addHdrLayerInfoListener(IBinder displayToken, IHdrLayerInfoListener listener);
+
+ /*
+ * Removes a listener that was added with addHdrLayerInfoListener.
+ *
+ * Returns NO_ERROR upon success, NAME_NOT_FOUND if the display is invalid, and BAD_VALUE if
+ * the listener wasn't registered.
+ *
+ */
+ void removeHdrLayerInfoListener(IBinder displayToken, IHdrLayerInfoListener listener);
+
+ /*
+ * Sends a power boost to the composer. This function is asynchronous.
+ *
+ * boostId
+ * boost id according to android::hardware::power::Boost
+ *
+ * Returns NO_ERROR upon success.
+ */
+ void notifyPowerBoost(int boostId);
}
diff --git a/libs/gui/aidl/android/gui/Rect.aidl b/libs/gui/aidl/android/gui/Rect.aidl
new file mode 100644
index 0000000..1b13761
--- /dev/null
+++ b/libs/gui/aidl/android/gui/Rect.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+package android.gui;
+
+// copied from libs/arect/include/android/rect.h
+// TODO(b/221473398):
+// use hardware/interfaces/graphics/common/aidl/android/hardware/graphics/common/Rect.aidl
+/** @hide */
+parcelable Rect {
+ /// Minimum X coordinate of the rectangle.
+ int left;
+
+ /// Minimum Y coordinate of the rectangle.
+ int top;
+
+ /// Maximum X coordinate of the rectangle.
+ int right;
+
+ /// Maximum Y coordinate of the rectangle.
+ int bottom;
+}
diff --git a/libs/gui/aidl/android/gui/Rotation.aidl b/libs/gui/aidl/android/gui/Rotation.aidl
new file mode 100644
index 0000000..451ff45
--- /dev/null
+++ b/libs/gui/aidl/android/gui/Rotation.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+package android.gui;
+
+/** @hide */
+@Backing(type="int")
+enum Rotation {
+ Rotation0 = 0,
+ Rotation90 = 1,
+ Rotation180 = 2,
+ Rotation270 = 3
+}
diff --git a/libs/gui/aidl/android/gui/Size.aidl b/libs/gui/aidl/android/gui/Size.aidl
new file mode 100644
index 0000000..415fa36
--- /dev/null
+++ b/libs/gui/aidl/android/gui/Size.aidl
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+package android.gui;
+
+/** @hide */
+parcelable Size {
+ int width = -1;
+ int height = -1;
+}
diff --git a/libs/gui/include/gui/HdrMetadata.h b/libs/gui/include/gui/HdrMetadata.h
index 0bdffac..98a07a3 100644
--- a/libs/gui/include/gui/HdrMetadata.h
+++ b/libs/gui/include/gui/HdrMetadata.h
@@ -17,6 +17,8 @@
#pragma once
#include <stdint.h>
+#include <ui/GraphicTypes.h>
+#include <optional>
#include <vector>
#include <system/graphics.h>
@@ -43,6 +45,27 @@
status_t flatten(void* buffer, size_t size) const;
status_t unflatten(void const* buffer, size_t size);
+ std::optional<ui::Smpte2086> getSmpte2086() const {
+ if (validTypes & Type::SMPTE2086) {
+ return ui::translate(smpte2086);
+ }
+ return {};
+ }
+
+ std::optional<ui::Cta861_3> getCta8613() const {
+ if (validTypes & Type::CTA861_3) {
+ return ui::translate(cta8613);
+ }
+ return {};
+ }
+
+ std::optional<std::vector<uint8_t>> getHdr10Plus() const {
+ if (validTypes & Type::HDR10PLUS) {
+ return hdr10plus;
+ }
+ return {};
+ }
+
bool operator==(const HdrMetadata& rhs) const;
bool operator!=(const HdrMetadata& rhs) const { return !(*this == rhs); }
};
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 0a3cc19..a610e94 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -27,7 +27,7 @@
#include <android/gui/IWindowInfosListener.h>
#include <binder/IBinder.h>
#include <binder/IInterface.h>
-#include <ftl/Flags.h>
+#include <ftl/flags.h>
#include <gui/FrameTimelineInfo.h>
#include <gui/ITransactionCompletedListener.h>
#include <gui/SpHash.h>
@@ -126,7 +126,7 @@
frameRateOverride = 1 << 1,
};
- using EventRegistrationFlags = Flags<EventRegistration>;
+ using EventRegistrationFlags = ftl::Flags<EventRegistration>;
/*
* Create a connection with SurfaceFlinger.
@@ -138,40 +138,6 @@
VsyncSource vsyncSource = eVsyncSourceApp,
EventRegistrationFlags eventRegistration = {}) = 0;
- /* create a virtual display
- * requires ACCESS_SURFACE_FLINGER permission.
- */
- virtual sp<IBinder> createDisplay(const String8& displayName,
- bool secure) = 0;
-
- /* destroy a virtual display
- * requires ACCESS_SURFACE_FLINGER permission.
- */
- virtual void destroyDisplay(const sp<IBinder>& display) = 0;
-
- /* get stable IDs for connected physical displays.
- */
- virtual std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const = 0;
-
- virtual status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const = 0;
-
- // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
- std::optional<PhysicalDisplayId> getInternalDisplayId() const {
- const auto displayIds = getPhysicalDisplayIds();
- return displayIds.empty() ? std::nullopt : std::make_optional(displayIds.front());
- }
-
- /* get token for a physical display given its stable ID obtained via getPhysicalDisplayIds or a
- * DisplayEventReceiver hotplug event.
- */
- virtual sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const = 0;
-
- // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
- sp<IBinder> getInternalDisplayToken() const {
- const auto displayId = getInternalDisplayId();
- return displayId ? getPhysicalDisplayToken(*displayId) : nullptr;
- }
-
/* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */
virtual status_t setTransactionState(
const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& state,
@@ -195,24 +161,6 @@
virtual status_t getSupportedFrameTimestamps(
std::vector<FrameEvent>* outSupported) const = 0;
- /* set display power mode. depending on the mode, it can either trigger
- * screen on, off or low power mode and wait for it to complete.
- * requires ACCESS_SURFACE_FLINGER permission.
- */
- virtual void setPowerMode(const sp<IBinder>& display, int mode) = 0;
-
-
- /* returns display statistics for a given display
- * intended to be used by the media framework to properly schedule
- * video frames */
- virtual status_t getDisplayStats(const sp<IBinder>& display,
- DisplayStatInfo* stats) = 0;
-
- /**
- * Get transactional state of given display.
- */
- virtual status_t getDisplayState(const sp<IBinder>& display, ui::DisplayState*) = 0;
-
/**
* Gets immutable information about given physical display.
*/
@@ -233,40 +181,6 @@
*/
virtual status_t setBootDisplayMode(const sp<IBinder>& display, ui::DisplayModeId) = 0;
- /**
- * Clears the user-preferred display mode. The device should now boot in system preferred
- * display mode.
- */
- virtual status_t clearBootDisplayMode(const sp<IBinder>& display) = 0;
-
- /**
- * Gets whether boot time display mode operations are supported on the device.
- *
- * outSupport
- * An output parameter for whether boot time display mode operations are supported.
- *
- * 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 getBootDisplayModeSupport(bool* outSupport) const = 0;
-
- /**
- * Switches Auto Low Latency Mode on/off on the connected display, if it is
- * available. This should only be called if the display supports Auto Low
- * Latency Mode as reported in #getDynamicDisplayInfo.
- * For more information, see the HDMI 2.1 specification.
- */
- virtual void setAutoLowLatencyMode(const sp<IBinder>& display, bool on) = 0;
-
- /**
- * This will start sending infoframes to the connected display with
- * ContentType=Game (if on=true). This should only be called if the display
- * Game Content Type as reported in #getDynamicDisplayInfo.
- * For more information, see the HDMI 1.4 specification.
- */
- virtual void setGameContentType(const sp<IBinder>& display, bool on) = 0;
-
/* Clears the frame statistics for animations.
*
* Requires the ACCESS_SURFACE_FLINGER permission.
@@ -345,13 +259,6 @@
*/
virtual status_t getProtectedContentSupport(bool* outSupported) const = 0;
- /*
- * Queries whether the given display is a wide color display.
- * Requires the ACCESS_SURFACE_FLINGER permission.
- */
- virtual status_t isWideColorDisplay(const sp<IBinder>& token,
- bool* outIsWideColorDisplay) const = 0;
-
/* Registers a listener to stream median luma updates from SurfaceFlinger.
*
* The sampling area is bounded by both samplingArea and the given stopLayerHandle
@@ -432,65 +339,6 @@
float* outPrimaryRefreshRateMax,
float* outAppRequestRefreshRateMin,
float* outAppRequestRefreshRateMax) = 0;
- /*
- * Gets whether brightness operations are supported on a display.
- *
- * displayToken
- * The token of the display.
- * outSupport
- * An output parameter for whether brightness operations are supported.
- *
- * 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 getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
- bool* outSupport) const = 0;
-
- /*
- * Sets the brightness of a display.
- *
- * displayToken
- * The token of the display whose brightness is set.
- * brightness
- * The DisplayBrightness info to set on the desired display.
- *
- * Returns NO_ERROR upon success. Otherwise,
- * NAME_NOT_FOUND if the display is invalid, or
- * BAD_VALUE if the brightness is invalid, or
- * INVALID_OPERATION if brightness operations are not supported.
- */
- virtual status_t setDisplayBrightness(const sp<IBinder>& displayToken,
- const gui::DisplayBrightness& brightness) = 0;
-
- /*
- * Adds a listener that receives HDR layer information. This is used in combination
- * with setDisplayBrightness to adjust the display brightness depending on factors such
- * as whether or not HDR is in use.
- *
- * Returns NO_ERROR upon success or NAME_NOT_FOUND if the display is invalid.
- */
- virtual status_t addHdrLayerInfoListener(const sp<IBinder>& displayToken,
- const sp<gui::IHdrLayerInfoListener>& listener) = 0;
- /*
- * Removes a listener that was added with addHdrLayerInfoListener.
- *
- * Returns NO_ERROR upon success, NAME_NOT_FOUND if the display is invalid, and BAD_VALUE if
- * the listener wasn't registered.
- *
- */
- virtual status_t removeHdrLayerInfoListener(const sp<IBinder>& displayToken,
- const sp<gui::IHdrLayerInfoListener>& listener) = 0;
-
- /*
- * Sends a power boost to the composer. This function is asynchronous.
- *
- * boostId
- * boost id according to android::hardware::power::Boost
- *
- * Returns NO_ERROR upon success.
- */
- virtual status_t notifyPowerBoost(int32_t boostId) = 0;
/*
* Sets the global configuration for all the shadows drawn by SurfaceFlinger. Shadow follows
@@ -597,9 +445,9 @@
CREATE_CONNECTION,
GET_STATIC_DISPLAY_INFO,
CREATE_DISPLAY_EVENT_CONNECTION,
- CREATE_DISPLAY,
- DESTROY_DISPLAY,
- GET_PHYSICAL_DISPLAY_TOKEN,
+ CREATE_DISPLAY, // Deprecated. Autogenerated by .aidl now.
+ DESTROY_DISPLAY, // Deprecated. Autogenerated by .aidl now.
+ GET_PHYSICAL_DISPLAY_TOKEN, // Deprecated. Autogenerated by .aidl now.
SET_TRANSACTION_STATE,
AUTHENTICATE_SURFACE,
GET_SUPPORTED_FRAME_TIMESTAMPS,
@@ -610,7 +458,7 @@
CAPTURE_LAYERS, // Deprecated. Autogenerated by .aidl now.
CLEAR_ANIMATION_FRAME_STATS,
GET_ANIMATION_FRAME_STATS,
- SET_POWER_MODE,
+ SET_POWER_MODE, // Deprecated. Autogenerated by .aidl now.
GET_DISPLAY_STATS,
GET_HDR_CAPABILITIES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
GET_DISPLAY_COLOR_MODES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
@@ -625,22 +473,22 @@
SET_DISPLAY_CONTENT_SAMPLING_ENABLED,
GET_DISPLAYED_CONTENT_SAMPLE,
GET_PROTECTED_CONTENT_SUPPORT,
- IS_WIDE_COLOR_DISPLAY,
+ IS_WIDE_COLOR_DISPLAY, // Deprecated. Autogenerated by .aidl now.
GET_DISPLAY_NATIVE_PRIMARIES,
- GET_PHYSICAL_DISPLAY_IDS,
+ GET_PHYSICAL_DISPLAY_IDS, // Deprecated. Autogenerated by .aidl now.
ADD_REGION_SAMPLING_LISTENER,
REMOVE_REGION_SAMPLING_LISTENER,
SET_DESIRED_DISPLAY_MODE_SPECS,
GET_DESIRED_DISPLAY_MODE_SPECS,
- GET_DISPLAY_BRIGHTNESS_SUPPORT,
- SET_DISPLAY_BRIGHTNESS,
- CAPTURE_DISPLAY_BY_ID, // Deprecated. Autogenerated by .aidl now.
- NOTIFY_POWER_BOOST,
+ GET_DISPLAY_BRIGHTNESS_SUPPORT, // Deprecated. Autogenerated by .aidl now.
+ SET_DISPLAY_BRIGHTNESS, // Deprecated. Autogenerated by .aidl now.
+ CAPTURE_DISPLAY_BY_ID, // Deprecated. Autogenerated by .aidl now.
+ NOTIFY_POWER_BOOST, // Deprecated. Autogenerated by .aidl now.
SET_GLOBAL_SHADOW_SETTINGS,
GET_AUTO_LOW_LATENCY_MODE_SUPPORT, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
- SET_AUTO_LOW_LATENCY_MODE,
- GET_GAME_CONTENT_TYPE_SUPPORT, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
- SET_GAME_CONTENT_TYPE,
+ SET_AUTO_LOW_LATENCY_MODE, // Deprecated. Autogenerated by .aidl now.
+ GET_GAME_CONTENT_TYPE_SUPPORT, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
+ SET_GAME_CONTENT_TYPE, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
SET_FRAME_RATE,
// Deprecated. Use DisplayManager.setShouldAlwaysRespectAppRequestedMode(true);
ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN,
@@ -652,18 +500,18 @@
ADD_FPS_LISTENER,
REMOVE_FPS_LISTENER,
OVERRIDE_HDR_TYPES,
- ADD_HDR_LAYER_INFO_LISTENER,
- REMOVE_HDR_LAYER_INFO_LISTENER,
+ ADD_HDR_LAYER_INFO_LISTENER, // Deprecated. Autogenerated by .aidl now.
+ REMOVE_HDR_LAYER_INFO_LISTENER, // Deprecated. Autogenerated by .aidl now.
ON_PULL_ATOM,
ADD_TUNNEL_MODE_ENABLED_LISTENER,
REMOVE_TUNNEL_MODE_ENABLED_LISTENER,
ADD_WINDOW_INFOS_LISTENER,
REMOVE_WINDOW_INFOS_LISTENER,
- GET_PRIMARY_PHYSICAL_DISPLAY_ID,
+ GET_PRIMARY_PHYSICAL_DISPLAY_ID, // Deprecated. Autogenerated by .aidl now.
GET_DISPLAY_DECORATION_SUPPORT,
- GET_BOOT_DISPLAY_MODE_SUPPORT,
+ GET_BOOT_DISPLAY_MODE_SUPPORT, // Deprecated. Autogenerated by .aidl now.
SET_BOOT_DISPLAY_MODE,
- CLEAR_BOOT_DISPLAY_MODE,
+ CLEAR_BOOT_DISPLAY_MODE, // Deprecated. Autogenerated by .aidl now.
SET_OVERRIDE_FRAME_RATE,
// Always append new enum to the end.
};
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 0f37dab..0a9b75a 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -29,6 +29,7 @@
#include <android/gui/DropInputMode.h>
#include <android/gui/FocusRequest.h>
+#include <ftl/flags.h>
#include <gui/DisplayCaptureArgs.h>
#include <gui/ISurfaceComposer.h>
#include <gui/LayerCaptureArgs.h>
@@ -102,7 +103,7 @@
// was called with.
sp<IBinder> releaseBufferEndpoint;
- Flags<BufferDataChange> flags;
+ ftl::Flags<BufferDataChange> flags;
client_cache_t cachedBuffer;
@@ -150,7 +151,7 @@
eTransparentRegionChanged = 0x00000020,
eFlagsChanged = 0x00000040,
eLayerStackChanged = 0x00000080,
- /* unused 0x00000400, */
+ eDimmingEnabledChanged = 0x00000400,
eShadowRadiusChanged = 0x00000800,
/* unused 0x00001000, */
eBufferCropChanged = 0x00002000,
@@ -187,7 +188,7 @@
eAutoRefreshChanged = 0x1000'00000000,
eStretchChanged = 0x2000'00000000,
eTrustedOverlayChanged = 0x4000'00000000,
- eDropInputModeChanged = 0x8000'00000000,
+ eDropInputModeChanged = 0x8000'00000000
};
layer_state_t();
@@ -298,6 +299,8 @@
// Force inputflinger to drop all input events for the layer and its children.
gui::DropInputMode dropInputMode;
+
+ bool dimmingEnabled;
};
struct ComposerState {
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 40d096e..ab9ebaa 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -35,6 +35,10 @@
namespace android {
+namespace gui {
+class ISurfaceComposer;
+} // namespace gui
+
class ISurfaceComposer;
/* This is the same as ProducerListener except that onBuffersDiscarded is
@@ -196,6 +200,7 @@
// Virtual for testing.
virtual sp<ISurfaceComposer> composerService() const;
+ virtual sp<gui::ISurfaceComposer> composerServiceAIDL() const;
virtual nsecs_t now() const;
private:
@@ -398,6 +403,13 @@
void getQueueBufferInputLocked(android_native_buffer_t* buffer, int fenceFd, nsecs_t timestamp,
IGraphicBufferProducer::QueueBufferInput* out);
+ // For easing in adoption of gralloc4 metadata by vendor components, as well as for supporting
+ // the public ANativeWindow api, allow setting relevant metadata when queueing a buffer through
+ // a native window
+ void applyGrallocMetadataLocked(
+ android_native_buffer_t* buffer,
+ const IGraphicBufferProducer::QueueBufferInput& queueBufferInput);
+
void onBufferQueuedLocked(int slot, sp<Fence> fence,
const IGraphicBufferProducer::QueueBufferOutput& output);
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 9d03f58..0cc43d8 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -491,6 +491,7 @@
uint32_t flags, uint32_t mask);
Transaction& setTransparentRegionHint(const sp<SurfaceControl>& sc,
const Region& transparentRegion);
+ Transaction& setDimmingEnabled(const sp<SurfaceControl>& sc, bool dimmingEnabled);
Transaction& setAlpha(const sp<SurfaceControl>& sc,
float alpha);
Transaction& setMatrix(const sp<SurfaceControl>& sc,
diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h
index ef0b98b..0e1d258 100644
--- a/libs/gui/include/gui/WindowInfo.h
+++ b/libs/gui/include/gui/WindowInfo.h
@@ -20,7 +20,7 @@
#include <android/os/InputConfig.h>
#include <binder/Parcel.h>
#include <binder/Parcelable.h>
-#include <ftl/Flags.h>
+#include <ftl/flags.h>
#include <gui/constants.h>
#include <ui/Rect.h>
#include <ui/Region.h>
@@ -224,7 +224,7 @@
int32_t ownerPid = -1;
int32_t ownerUid = -1;
std::string packageName;
- Flags<InputConfig> inputConfig;
+ ftl::Flags<InputConfig> inputConfig;
int32_t displayId = ADISPLAY_ID_NONE;
InputApplicationInfo applicationInfo;
bool replaceTouchableRegionWithCrop = false;
@@ -232,9 +232,9 @@
// The window's layout params flags and type set by WM.
Type layoutParamsType = Type::UNKNOWN;
- Flags<Flag> layoutParamsFlags;
+ ftl::Flags<Flag> layoutParamsFlags;
- void setInputConfig(Flags<InputConfig> config, bool value);
+ void setInputConfig(ftl::Flags<InputConfig> config, bool value);
void addTouchableRegion(const Rect& region);
diff --git a/libs/gui/include/private/gui/ComposerServiceAIDL.h b/libs/gui/include/private/gui/ComposerServiceAIDL.h
index fee37ee..9a96976 100644
--- a/libs/gui/include/private/gui/ComposerServiceAIDL.h
+++ b/libs/gui/include/private/gui/ComposerServiceAIDL.h
@@ -50,6 +50,28 @@
// Get a connection to the Composer Service. This will block until
// a connection is established. Returns null if permission is denied.
static sp<gui::ISurfaceComposer> getComposerService();
+
+ // the following two methods are moved from ISurfaceComposer.h
+ // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
+ std::optional<PhysicalDisplayId> getInternalDisplayId() const {
+ std::vector<int64_t> displayIds;
+ binder::Status status = mComposerService->getPhysicalDisplayIds(&displayIds);
+ return (!status.isOk() || displayIds.empty())
+ ? std::nullopt
+ : DisplayId::fromValue<PhysicalDisplayId>(
+ static_cast<uint64_t>(displayIds.front()));
+ }
+
+ // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
+ sp<IBinder> getInternalDisplayToken() const {
+ const auto displayId = getInternalDisplayId();
+ if (!displayId) return nullptr;
+ sp<IBinder> display;
+ binder::Status status =
+ mComposerService->getPhysicalDisplayToken(static_cast<int64_t>(displayId->value),
+ &display);
+ return status.isOk() ? display : nullptr;
+ }
};
// ---------------------------------------------------------------------------
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index a885e92..065cd7a 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -20,6 +20,7 @@
#include <SurfaceFlingerProperties.h>
#include <android/gui/IDisplayEventConnection.h>
+#include <android/gui/ISurfaceComposer.h>
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <binder/ProcessState.h>
#include <configstore/Utils.h>
@@ -260,9 +261,7 @@
sp<ANativeWindow> anw(mSurface);
// Verify the screenshot works with no protected buffers.
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-
- const sp<IBinder> display = sf->getInternalDisplayToken();
+ const sp<IBinder> display = ComposerServiceAIDL::getInstance().getInternalDisplayToken();
ASSERT_FALSE(display == nullptr);
DisplayCaptureArgs captureArgs;
@@ -696,12 +695,6 @@
ISurfaceComposer::VsyncSource, ISurfaceComposer::EventRegistrationFlags) override {
return nullptr;
}
- sp<IBinder> createDisplay(const String8& /*displayName*/,
- bool /*secure*/) override { return nullptr; }
- void destroyDisplay(const sp<IBinder>& /*display */) override {}
- std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override { return {}; }
- status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const override { return NO_ERROR; }
- sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId) const override { return nullptr; }
status_t setTransactionState(const FrameTimelineInfo& /*frameTimelineInfo*/,
const Vector<ComposerState>& /*state*/,
const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/,
@@ -740,7 +733,6 @@
return NO_ERROR;
}
- void setPowerMode(const sp<IBinder>& /*display*/, int /*mode*/) override {}
status_t getStaticDisplayInfo(const sp<IBinder>& /*display*/, ui::StaticDisplayInfo*) override {
return NO_ERROR;
}
@@ -748,24 +740,16 @@
ui::DynamicDisplayInfo*) override {
return NO_ERROR;
}
- status_t getDisplayState(const sp<IBinder>& /*display*/, ui::DisplayState*) override {
- return NO_ERROR;
- }
- status_t getDisplayStats(const sp<IBinder>& /*display*/,
- DisplayStatInfo* /*stats*/) override { return NO_ERROR; }
status_t getDisplayNativePrimaries(const sp<IBinder>& /*display*/,
ui::DisplayPrimaries& /*primaries*/) override {
return NO_ERROR;
}
- status_t setActiveColorMode(const sp<IBinder>& /*display*/,
- ColorMode /*colorMode*/) override { return NO_ERROR; }
- status_t getBootDisplayModeSupport(bool* /*outSupport*/) const override { return NO_ERROR; }
+ status_t setActiveColorMode(const sp<IBinder>& /*display*/, ColorMode /*colorMode*/) override {
+ return NO_ERROR;
+ }
status_t setBootDisplayMode(const sp<IBinder>& /*display*/, ui::DisplayModeId /*id*/) override {
return NO_ERROR;
}
- status_t clearBootDisplayMode(const sp<IBinder>& /*display*/) override { return NO_ERROR; }
- void setAutoLowLatencyMode(const sp<IBinder>& /*display*/, bool /*on*/) override {}
- void setGameContentType(const sp<IBinder>& /*display*/, bool /*on*/) override {}
status_t clearAnimationFrameStats() override { return NO_ERROR; }
status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override {
@@ -812,26 +796,6 @@
status_t getColorManagement(bool* /*outGetColorManagement*/) const override { return NO_ERROR; }
status_t getProtectedContentSupport(bool* /*outSupported*/) const override { return NO_ERROR; }
- status_t isWideColorDisplay(const sp<IBinder>&, bool*) const override { return NO_ERROR; }
- status_t getDisplayBrightnessSupport(const sp<IBinder>& /*displayToken*/,
- bool* /*outSupport*/) const override {
- return NO_ERROR;
- }
- status_t setDisplayBrightness(const sp<IBinder>& /*displayToken*/,
- const gui::DisplayBrightness& /*brightness*/) override {
- return NO_ERROR;
- }
-
- status_t addHdrLayerInfoListener(const sp<IBinder>&,
- const sp<gui::IHdrLayerInfoListener>&) override {
- return NO_ERROR;
- }
-
- status_t removeHdrLayerInfoListener(const sp<IBinder>&,
- const sp<gui::IHdrLayerInfoListener>&) override {
- return NO_ERROR;
- }
-
status_t addRegionSamplingListener(const Rect& /*samplingArea*/,
const sp<IBinder>& /*stopLayerHandle*/,
const sp<IRegionSamplingListener>& /*listener*/) override {
@@ -873,7 +837,6 @@
float* /*outAppRequestRefreshRateMax*/) override {
return NO_ERROR;
};
- status_t notifyPowerBoost(int32_t /*boostId*/) override { return NO_ERROR; }
status_t setGlobalShadowSettings(const half4& /*ambientColor*/, const half4& /*spotColor*/,
float /*lightPosY*/, float /*lightPosZ*/,
@@ -925,6 +888,114 @@
bool mSupportsPresent{true};
};
+class FakeSurfaceComposerAIDL : public gui::ISurfaceComposer {
+public:
+ ~FakeSurfaceComposerAIDL() override {}
+
+ void setSupportsPresent(bool supportsPresent) { mSupportsPresent = supportsPresent; }
+
+ binder::Status createDisplay(const std::string& /*displayName*/, bool /*secure*/,
+ sp<IBinder>* /*outDisplay*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status destroyDisplay(const sp<IBinder>& /*display*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status getPhysicalDisplayIds(std::vector<int64_t>* /*outDisplayIds*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status getPrimaryPhysicalDisplayId(int64_t* /*outDisplayId*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status getPhysicalDisplayToken(int64_t /*displayId*/,
+ sp<IBinder>* /*outDisplay*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status setPowerMode(const sp<IBinder>& /*display*/, int /*mode*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status getDisplayStats(const sp<IBinder>& /*display*/,
+ gui::DisplayStatInfo* /*outStatInfo*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status getDisplayState(const sp<IBinder>& /*display*/,
+ gui::DisplayState* /*outState*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status clearBootDisplayMode(const sp<IBinder>& /*display*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status getBootDisplayModeSupport(bool* /*outMode*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status setAutoLowLatencyMode(const sp<IBinder>& /*display*/, bool /*on*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status setGameContentType(const sp<IBinder>& /*display*/, bool /*on*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status captureDisplay(const DisplayCaptureArgs&,
+ const sp<IScreenCaptureListener>&) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status captureDisplayById(int64_t, const sp<IScreenCaptureListener>&) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status captureLayers(const LayerCaptureArgs&,
+ const sp<IScreenCaptureListener>&) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status isWideColorDisplay(const sp<IBinder>& /*token*/,
+ bool* /*outIsWideColorDisplay*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status getDisplayBrightnessSupport(const sp<IBinder>& /*displayToken*/,
+ bool* /*outSupport*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status setDisplayBrightness(const sp<IBinder>& /*displayToken*/,
+ const gui::DisplayBrightness& /*brightness*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status addHdrLayerInfoListener(
+ const sp<IBinder>& /*displayToken*/,
+ const sp<gui::IHdrLayerInfoListener>& /*listener*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status removeHdrLayerInfoListener(
+ const sp<IBinder>& /*displayToken*/,
+ const sp<gui::IHdrLayerInfoListener>& /*listener*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status notifyPowerBoost(int /*boostId*/) override { return binder::Status::ok(); }
+
+protected:
+ IBinder* onAsBinder() override { return nullptr; }
+
+private:
+ bool mSupportsPresent{true};
+};
+
class FakeProducerFrameEventHistory : public ProducerFrameEventHistory {
public:
explicit FakeProducerFrameEventHistory(FenceToFenceTimeMap* fenceMap) : mFenceMap(fenceMap) {}
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 18fb7c1..5d7874a 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -50,6 +50,7 @@
"Keyboard.cpp",
"KeyCharacterMap.cpp",
"KeyLayoutMap.cpp",
+ "PrintTools.cpp",
"PropertyMap.cpp",
"TouchVideoFrame.cpp",
"VelocityControl.cpp",
diff --git a/libs/input/PrintTools.cpp b/libs/input/PrintTools.cpp
new file mode 100644
index 0000000..5d6ae4e
--- /dev/null
+++ b/libs/input/PrintTools.cpp
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "PrintTools"
+
+#include <input/PrintTools.h>
+
+namespace android {
+
+const char* toString(bool value) {
+ return value ? "true" : "false";
+}
+
+} // namespace android
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index a6465ee..7f427f2 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -15,13 +15,6 @@
*/
#define LOG_TAG "VelocityTracker"
-//#define LOG_NDEBUG 0
-
-// Log debug messages about velocity tracking.
-static constexpr bool DEBUG_VELOCITY = false;
-
-// Log debug messages about the progress of the algorithm itself.
-static constexpr bool DEBUG_STRATEGY = false;
#include <array>
#include <inttypes.h>
@@ -36,6 +29,27 @@
namespace android {
+/**
+ * Log debug messages about velocity tracking.
+ * Enable this via "adb shell setprop log.tag.VelocityTrackerVelocity DEBUG" (requires restart)
+ */
+const bool DEBUG_VELOCITY =
+ __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Velocity", ANDROID_LOG_INFO);
+
+/**
+ * Log debug messages about the progress of the algorithm itself.
+ * Enable this via "adb shell setprop log.tag.VelocityTrackerStrategy DEBUG" (requires restart)
+ */
+const bool DEBUG_STRATEGY =
+ __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Strategy", ANDROID_LOG_INFO);
+
+/**
+ * Log debug messages about the 'impulse' strategy.
+ * Enable this via "adb shell setprop log.tag.VelocityTrackerImpulse DEBUG" (requires restart)
+ */
+const bool DEBUG_IMPULSE =
+ __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Impulse", ANDROID_LOG_INFO);
+
// Nanoseconds per milliseconds.
static const nsecs_t NANOS_PER_MS = 1000000;
@@ -141,7 +155,7 @@
return std::make_unique<LeastSquaresVelocityTrackerStrategy>(1);
case VelocityTracker::Strategy::LSQ2:
- if (DEBUG_STRATEGY) {
+ if (DEBUG_STRATEGY && !DEBUG_IMPULSE) {
ALOGI("Initializing lsq2 strategy");
}
return std::make_unique<LeastSquaresVelocityTrackerStrategy>(2);
@@ -1172,7 +1186,25 @@
outEstimator->degree = 2; // similar results to 2nd degree fit
outEstimator->confidence = 1;
if (DEBUG_STRATEGY) {
- ALOGD("velocity: (%f, %f)", outEstimator->xCoeff[1], outEstimator->yCoeff[1]);
+ ALOGD("velocity: (%.1f, %.1f)", outEstimator->xCoeff[1], outEstimator->yCoeff[1]);
+ }
+ if (DEBUG_IMPULSE) {
+ // TODO(b/134179997): delete this block once the switch to 'impulse' is complete.
+ // Calculate the lsq2 velocity for the same inputs to allow runtime comparisons
+ VelocityTracker lsq2(VelocityTracker::Strategy::LSQ2);
+ BitSet32 idBits;
+ const uint32_t pointerId = 0;
+ idBits.markBit(pointerId);
+ for (ssize_t i = m - 1; i >= 0; i--) {
+ lsq2.addMovement(time[i], idBits, {{x[i], y[i]}});
+ }
+ float outVx = 0, outVy = 0;
+ const bool computed = lsq2.getVelocity(pointerId, &outVx, &outVy);
+ if (computed) {
+ ALOGD("lsq2 velocity: (%.1f, %.1f)", outVx, outVy);
+ } else {
+ ALOGD("lsq2 velocity: could not compute velocity");
+ }
}
return true;
}
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 381900e..4a1784e 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -207,7 +207,11 @@
if (result == 0) {
outPlanes->planeCount = 3;
outPlanes->planes[0].data = yuvData.y;
- outPlanes->planes[0].pixelStride = 1;
+ if (format == AHARDWAREBUFFER_FORMAT_YCbCr_P010) {
+ outPlanes->planes[0].pixelStride = 2;
+ } else {
+ outPlanes->planes[0].pixelStride = 1;
+ }
outPlanes->planes[0].rowStride = yuvData.ystride;
outPlanes->planes[1].data = yuvData.cb;
outPlanes->planes[1].pixelStride = yuvData.chroma_step;
diff --git a/libs/nativewindow/include/apex/window.h b/libs/nativewindow/include/apex/window.h
index 0923438..2d1354c 100644
--- a/libs/nativewindow/include/apex/window.h
+++ b/libs/nativewindow/include/apex/window.h
@@ -39,19 +39,6 @@
// clang-format on
};
-/*
- * Internal extension of compatibility value for ANativeWindow_setFrameRate. */
-enum ANativeWindow_FrameRateCompatibilityInternal {
- /**
- * This surface belongs to an app on the High Refresh Rate Deny list, and needs the display
- * to operate at the exact frame rate.
- *
- * This is used internally by the platform and should not be used by apps.
- * @hide
- */
- ANATIVEWINDOW_FRAME_RATE_EXACT = 100,
-};
-
/**
* Prototype of the function that an ANativeWindow implementation would call
* when ANativeWindow_cancelBuffer is called.
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index a319769..a54af1f 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -1018,6 +1018,24 @@
return window->perform(window, NATIVE_WINDOW_SET_AUTO_PREROTATION, autoPrerotation);
}
+/*
+ * Internal extension of ANativeWindow_FrameRateCompatibility.
+ */
+enum {
+ /**
+ * This surface belongs to an app on the High Refresh Rate Deny list, and needs the display
+ * to operate at the exact frame rate.
+ *
+ * Keep in sync with Surface.java constant.
+ */
+ ANATIVEWINDOW_FRAME_RATE_EXACT = 100,
+
+ /**
+ * This surface is ignored while choosing the refresh rate.
+ */
+ ANATIVEWINDOW_FRAME_RATE_NO_VOTE,
+};
+
static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate,
int8_t compatibility, int8_t changeFrameRateStrategy) {
return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, (double)frameRate,
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index 84e84dd..cb92df3 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -27,6 +27,7 @@
"-DEGL_EGLEXT_PROTOTYPES",
],
shared_libs: [
+ "android.hardware.graphics.composer3-V1-ndk",
"libbase",
"libcutils",
"libEGL",
diff --git a/libs/renderengine/benchmark/Android.bp b/libs/renderengine/benchmark/Android.bp
index 471159f..249fec5 100644
--- a/libs/renderengine/benchmark/Android.bp
+++ b/libs/renderengine/benchmark/Android.bp
@@ -43,6 +43,7 @@
],
shared_libs: [
+ "android.hardware.graphics.composer3-V1-ndk",
"libbase",
"libcutils",
"libjnigraphics",
diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h
index 40ba5ad..a5e0879 100644
--- a/libs/renderengine/include/renderengine/DisplaySettings.h
+++ b/libs/renderengine/include/renderengine/DisplaySettings.h
@@ -16,6 +16,8 @@
#pragma once
+#include <aidl/android/hardware/graphics/composer3/DimmingStage.h>
+#include <aidl/android/hardware/graphics/composer3/RenderIntent.h>
#include <iosfwd>
#include <math/mat4.h>
@@ -68,6 +70,14 @@
// All layers will be dimmed by (max(layer white points) / targetLuminanceNits).
// If the target luminance is unknown, then no display-level dimming occurs.
float targetLuminanceNits = -1.f;
+
+ // Configures when dimming should be applied for each layer.
+ aidl::android::hardware::graphics::composer3::DimmingStage dimmingStage =
+ aidl::android::hardware::graphics::composer3::DimmingStage::NONE;
+
+ // Configures the rendering intent of the output display. This is used for tonemapping.
+ aidl::android::hardware::graphics::composer3::RenderIntent renderIntent =
+ aidl::android::hardware::graphics::composer3::RenderIntent::TONE_MAP_COLORIMETRIC;
};
static inline bool operator==(const DisplaySettings& lhs, const DisplaySettings& rhs) {
diff --git a/libs/renderengine/skia/ColorSpaces.cpp b/libs/renderengine/skia/ColorSpaces.cpp
index f367a84..37ff5df 100644
--- a/libs/renderengine/skia/ColorSpaces.cpp
+++ b/libs/renderengine/skia/ColorSpaces.cpp
@@ -65,7 +65,15 @@
case HAL_DATASPACE_TRANSFER_SMPTE_170M:
return SkColorSpace::MakeRGB(SkNamedTransferFn::kRec2020, gamut);
case HAL_DATASPACE_TRANSFER_HLG:
- return SkColorSpace::MakeRGB(SkNamedTransferFn::kHLG, gamut);
+ // return HLG transfer but scale by 1/12
+ skcms_TransferFunction hlgFn;
+ if (skcms_TransferFunction_makeScaledHLGish(&hlgFn, 1.f / 12.f, 2.f, 2.f,
+ 1.f / 0.17883277f, 0.28466892f,
+ 0.55991073f)) {
+ return SkColorSpace::MakeRGB(hlgFn, gamut);
+ } else {
+ return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut);
+ }
case HAL_DATASPACE_TRANSFER_UNSPECIFIED:
default:
return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut);
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 1665550..9bb68e3 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -39,6 +39,7 @@
#include <gui/TraceUtils.h>
#include <sync/sync.h>
#include <ui/BlurRegion.h>
+#include <ui/DataspaceUtils.h>
#include <ui/DebugUtils.h>
#include <ui/GraphicBuffer.h>
#include <utils/Trace.h>
@@ -291,6 +292,8 @@
void SkiaGLRenderEngine::SkSLCacheMonitor::store(const SkData& key, const SkData& data,
const SkString& description) {
mShadersCachedSinceLastCall++;
+ mTotalShadersCompiled++;
+ ATRACE_FORMAT("SF cache: %i shaders", mTotalShadersCompiled);
}
void SkiaGLRenderEngine::assertShadersCompiled(int numShaders) {
@@ -661,7 +664,7 @@
parameters.display.maxLuminance,
parameters.display.currentLuminanceNits,
parameters.layer.source.buffer.maxLuminanceNits,
- hardwareBuffer);
+ hardwareBuffer, parameters.display.renderIntent);
}
return parameters.shader;
}
@@ -736,7 +739,9 @@
return roundedRect;
}
-static bool equalsWithinMargin(float expected, float value, float margin) {
+// Arbitrary default margin which should be close enough to zero.
+constexpr float kDefaultMargin = 0.0001f;
+static bool equalsWithinMargin(float expected, float value, float margin = kDefaultMargin) {
LOG_ALWAYS_FATAL_IF(margin < 0.f, "Margin is negative!");
return std::abs(expected - value) < margin;
}
@@ -994,10 +999,13 @@
? displayDimmingRatio
: (layer.whitePointNits / maxLayerWhitePoint) * displayDimmingRatio;
+ const bool dimInLinearSpace = display.dimmingStage !=
+ aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF;
+
const bool requiresLinearEffect = layer.colorTransform != mat4() ||
(mUseColorManagement &&
needsToneMapping(layer.sourceDataspace, display.outputDataspace)) ||
- !equalsWithinMargin(1.f, layerDimmingRatio, 0.001f);
+ (dimInLinearSpace && !equalsWithinMargin(1.f, layerDimmingRatio));
// quick abort from drawing the remaining portion of the layer
if (layer.skipContentDraw ||
@@ -1103,11 +1111,19 @@
.undoPremultipliedAlpha = !item.isOpaque &&
item.usePremultipliedAlpha,
.requiresLinearEffect = requiresLinearEffect,
- .layerDimmingRatio = layerDimmingRatio}));
+ .layerDimmingRatio = dimInLinearSpace
+ ? layerDimmingRatio
+ : 1.f}));
- // Turn on dithering when dimming beyond this threshold.
+ // Turn on dithering when dimming beyond this (arbitrary) threshold...
static constexpr float kDimmingThreshold = 0.2f;
- if (layerDimmingRatio <= kDimmingThreshold) {
+ // ...or we're rendering an HDR layer down to an 8-bit target
+ // Most HDR standards require at least 10-bits of color depth for source content, so we
+ // can just extract the transfer function rather than dig into precise gralloc layout.
+ // Furthermore, we can assume that the only 8-bit target we support is RGBA8888.
+ const bool requiresDownsample = isHdrDataspace(layer.sourceDataspace) &&
+ buffer->getPixelFormat() == PIXEL_FORMAT_RGBA_8888;
+ if (layerDimmingRatio <= kDimmingThreshold || requiresDownsample) {
paint.setDither(true);
}
paint.setAlphaf(layer.alpha);
@@ -1170,7 +1186,20 @@
// An A8 buffer will already have the proper color filter attached to
// its paint, including the displayColorTransform as needed.
if (!paint.getColorFilter()) {
- paint.setColorFilter(displayColorTransform);
+ if (!dimInLinearSpace && !equalsWithinMargin(1.0, layerDimmingRatio)) {
+ // If we don't dim in linear space, then when we gamma correct the dimming ratio we
+ // can assume a gamma 2.2 transfer function.
+ static constexpr float kInverseGamma22 = 1.f / 2.2f;
+ const auto gammaCorrectedDimmingRatio =
+ std::pow(layerDimmingRatio, kInverseGamma22);
+ const auto dimmingMatrix =
+ mat4::scale(vec4(gammaCorrectedDimmingRatio, gammaCorrectedDimmingRatio,
+ gammaCorrectedDimmingRatio, 1.f));
+ paint.setColorFilter(SkColorFilters::Matrix(
+ toSkColorMatrix(display.colorTransform * dimmingMatrix)));
+ } else {
+ paint.setColorFilter(displayColorTransform);
+ }
}
if (!roundRectClip.isEmpty()) {
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index a650313..56815fe 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -180,6 +180,7 @@
private:
int mShadersCachedSinceLastCall = 0;
+ int mTotalShadersCompiled = 0;
};
SkSLCacheMonitor mSkSLCacheMonitor;
diff --git a/libs/renderengine/skia/filters/LinearEffect.cpp b/libs/renderengine/skia/filters/LinearEffect.cpp
index d479606..f7dcd3a 100644
--- a/libs/renderengine/skia/filters/LinearEffect.cpp
+++ b/libs/renderengine/skia/filters/LinearEffect.cpp
@@ -40,12 +40,11 @@
return shader;
}
-sk_sp<SkShader> createLinearEffectShader(sk_sp<SkShader> shader,
- const shaders::LinearEffect& linearEffect,
- sk_sp<SkRuntimeEffect> runtimeEffect,
- const mat4& colorTransform, float maxDisplayLuminance,
- float currentDisplayLuminanceNits, float maxLuminance,
- AHardwareBuffer* buffer) {
+sk_sp<SkShader> createLinearEffectShader(
+ sk_sp<SkShader> shader, const shaders::LinearEffect& linearEffect,
+ sk_sp<SkRuntimeEffect> runtimeEffect, const mat4& colorTransform, float maxDisplayLuminance,
+ float currentDisplayLuminanceNits, float maxLuminance, AHardwareBuffer* buffer,
+ aidl::android::hardware::graphics::composer3::RenderIntent renderIntent) {
ATRACE_CALL();
SkRuntimeShaderBuilder effectBuilder(runtimeEffect);
@@ -53,7 +52,8 @@
const auto uniforms =
shaders::buildLinearEffectUniforms(linearEffect, colorTransform, maxDisplayLuminance,
- currentDisplayLuminanceNits, maxLuminance, buffer);
+ currentDisplayLuminanceNits, maxLuminance, buffer,
+ renderIntent);
for (const auto& uniform : uniforms) {
effectBuilder.uniform(uniform.name.c_str()).set(uniform.value.data(), uniform.value.size());
diff --git a/libs/renderengine/skia/filters/LinearEffect.h b/libs/renderengine/skia/filters/LinearEffect.h
index 26bae3b..3c66c51 100644
--- a/libs/renderengine/skia/filters/LinearEffect.h
+++ b/libs/renderengine/skia/filters/LinearEffect.h
@@ -42,12 +42,13 @@
// or as the max light level from the CTA 861.3 standard.
// * An AHardwareBuffer for implementations that support gralloc4 metadata for
// communicating any HDR metadata.
-sk_sp<SkShader> createLinearEffectShader(sk_sp<SkShader> inputShader,
- const shaders::LinearEffect& linearEffect,
- sk_sp<SkRuntimeEffect> runtimeEffect,
- const mat4& colorTransform, float maxDisplayLuminance,
- float currentDisplayLuminanceNits, float maxLuminance,
- AHardwareBuffer* buffer);
+// * A RenderIntent that communicates the downstream renderintent for a physical display, for image
+// quality compensation.
+sk_sp<SkShader> createLinearEffectShader(
+ sk_sp<SkShader> inputShader, const shaders::LinearEffect& linearEffect,
+ sk_sp<SkRuntimeEffect> runtimeEffect, const mat4& colorTransform, float maxDisplayLuminance,
+ float currentDisplayLuminanceNits, float maxLuminance, AHardwareBuffer* buffer,
+ aidl::android::hardware::graphics::composer3::RenderIntent renderIntent);
} // namespace skia
} // namespace renderengine
} // namespace android
diff --git a/libs/renderengine/tests/Android.bp b/libs/renderengine/tests/Android.bp
index d91af1e..e66fee1 100644
--- a/libs/renderengine/tests/Android.bp
+++ b/libs/renderengine/tests/Android.bp
@@ -47,6 +47,7 @@
],
shared_libs: [
+ "android.hardware.graphics.composer3-V1-ndk",
"libbase",
"libcutils",
"libEGL",
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 38ae2fd..2493242 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -2405,15 +2405,18 @@
TEST_P(RenderEngineTest, testDimming) {
if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
- return;
+ GTEST_SKIP();
}
+
initializeRenderEngine();
+ const ui::Dataspace dataspace = ui::Dataspace::V0_SRGB_LINEAR;
+
const auto displayRect = Rect(3, 1);
const renderengine::DisplaySettings display{
.physicalDisplay = displayRect,
.clip = displayRect,
- .outputDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+ .outputDataspace = dataspace,
.targetLuminanceNits = 1000.f,
};
@@ -2432,7 +2435,7 @@
},
},
.alpha = 1.0f,
- .sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+ .sourceDataspace = dataspace,
.whitePointNits = 200.f,
};
@@ -2447,7 +2450,7 @@
},
},
.alpha = 1.0f,
- .sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+ .sourceDataspace = dataspace,
.whitePointNits = 1000.f / 51.f,
};
@@ -2462,7 +2465,7 @@
},
},
.alpha = 1.0f,
- .sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+ .sourceDataspace = dataspace,
// When the white point is not set for a layer, just ignore it and treat it as the same
// as the max layer
.whitePointNits = -1.f,
@@ -2476,6 +2479,84 @@
expectBufferColor(Rect(2, 0, 3, 1), 51, 0, 0, 255, 1);
}
+TEST_P(RenderEngineTest, testDimming_inGammaSpace) {
+ if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
+ GTEST_SKIP();
+ }
+ initializeRenderEngine();
+
+ const ui::Dataspace dataspace = static_cast<ui::Dataspace>(ui::Dataspace::STANDARD_BT709 |
+ ui::Dataspace::TRANSFER_GAMMA2_2 |
+ ui::Dataspace::RANGE_FULL);
+
+ const auto displayRect = Rect(3, 1);
+ const renderengine::DisplaySettings display{
+ .physicalDisplay = displayRect,
+ .clip = displayRect,
+ .outputDataspace = dataspace,
+ .targetLuminanceNits = 1000.f,
+ .dimmingStage = aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF,
+ };
+
+ const auto greenBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 255, 0, 255));
+ const auto blueBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 0, 255, 255));
+ const auto redBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(255, 0, 0, 255));
+
+ const renderengine::LayerSettings greenLayer{
+ .geometry.boundaries = FloatRect(0.f, 0.f, 1.f, 1.f),
+ .source =
+ renderengine::PixelSource{
+ .buffer =
+ renderengine::Buffer{
+ .buffer = greenBuffer,
+ .usePremultipliedAlpha = true,
+ },
+ },
+ .alpha = 1.0f,
+ .sourceDataspace = dataspace,
+ .whitePointNits = 200.f,
+ };
+
+ const renderengine::LayerSettings blueLayer{
+ .geometry.boundaries = FloatRect(1.f, 0.f, 2.f, 1.f),
+ .source =
+ renderengine::PixelSource{
+ .buffer =
+ renderengine::Buffer{
+ .buffer = blueBuffer,
+ .usePremultipliedAlpha = true,
+ },
+ },
+ .alpha = 1.0f,
+ .sourceDataspace = dataspace,
+ .whitePointNits = 1000.f / 51.f,
+ };
+
+ const renderengine::LayerSettings redLayer{
+ .geometry.boundaries = FloatRect(2.f, 0.f, 3.f, 1.f),
+ .source =
+ renderengine::PixelSource{
+ .buffer =
+ renderengine::Buffer{
+ .buffer = redBuffer,
+ .usePremultipliedAlpha = true,
+ },
+ },
+ .alpha = 1.0f,
+ .sourceDataspace = dataspace,
+ // When the white point is not set for a layer, just ignore it and treat it as the same
+ // as the max layer
+ .whitePointNits = -1.f,
+ };
+
+ std::vector<renderengine::LayerSettings> layers{greenLayer, blueLayer, redLayer};
+ invokeDraw(display, layers);
+
+ expectBufferColor(Rect(1, 1), 0, 122, 0, 255, 1);
+ expectBufferColor(Rect(1, 0, 2, 1), 0, 0, 42, 255, 1);
+ expectBufferColor(Rect(2, 0, 3, 1), 122, 0, 0, 255, 1);
+}
+
TEST_P(RenderEngineTest, testDimming_withoutTargetLuminance) {
initializeRenderEngine();
if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
diff --git a/libs/shaders/Android.bp b/libs/shaders/Android.bp
index 2f8bf49..6b936de 100644
--- a/libs/shaders/Android.bp
+++ b/libs/shaders/Android.bp
@@ -29,6 +29,7 @@
shared_libs: [
"android.hardware.graphics.common-V3-ndk",
+ "android.hardware.graphics.composer3-V1-ndk",
"android.hardware.graphics.common@1.2",
"libnativewindow",
],
diff --git a/libs/shaders/include/shaders/shaders.h b/libs/shaders/include/shaders/shaders.h
index 4ec7594..2a4a370 100644
--- a/libs/shaders/include/shaders/shaders.h
+++ b/libs/shaders/include/shaders/shaders.h
@@ -97,11 +97,10 @@
std::string buildLinearEffectSkSL(const LinearEffect& linearEffect);
// Generates a list of uniforms to set on the LinearEffect shader above.
-std::vector<tonemap::ShaderUniform> buildLinearEffectUniforms(const LinearEffect& linearEffect,
- const mat4& colorTransform,
- float maxDisplayLuminance,
- float currentDisplayLuminanceNits,
- float maxLuminance,
- AHardwareBuffer* buffer = nullptr);
+std::vector<tonemap::ShaderUniform> buildLinearEffectUniforms(
+ const LinearEffect& linearEffect, const mat4& colorTransform, float maxDisplayLuminance,
+ float currentDisplayLuminanceNits, float maxLuminance, AHardwareBuffer* buffer = nullptr,
+ aidl::android::hardware::graphics::composer3::RenderIntent renderIntent =
+ aidl::android::hardware::graphics::composer3::RenderIntent::TONE_MAP_COLORIMETRIC);
} // namespace android::shaders
diff --git a/libs/shaders/shaders.cpp b/libs/shaders/shaders.cpp
index 5935589..f0d45c2 100644
--- a/libs/shaders/shaders.cpp
+++ b/libs/shaders/shaders.cpp
@@ -464,12 +464,10 @@
}
// Generates a list of uniforms to set on the LinearEffect shader above.
-std::vector<tonemap::ShaderUniform> buildLinearEffectUniforms(const LinearEffect& linearEffect,
- const mat4& colorTransform,
- float maxDisplayLuminance,
- float currentDisplayLuminanceNits,
- float maxLuminance,
- AHardwareBuffer* buffer) {
+std::vector<tonemap::ShaderUniform> buildLinearEffectUniforms(
+ const LinearEffect& linearEffect, const mat4& colorTransform, float maxDisplayLuminance,
+ float currentDisplayLuminanceNits, float maxLuminance, AHardwareBuffer* buffer,
+ aidl::android::hardware::graphics::composer3::RenderIntent renderIntent) {
std::vector<tonemap::ShaderUniform> uniforms;
if (linearEffect.inputDataspace == linearEffect.outputDataspace) {
uniforms.push_back({.name = "in_rgbToXyz", .value = buildUniformValue<mat4>(mat4())});
@@ -495,7 +493,8 @@
.currentDisplayLuminance = currentDisplayLuminanceNits > 0
? currentDisplayLuminanceNits
: maxDisplayLuminance,
- .buffer = buffer};
+ .buffer = buffer,
+ .renderIntent = renderIntent};
for (const auto uniform : tonemap::getToneMapper()->generateShaderSkSLUniforms(metadata)) {
uniforms.push_back(uniform);
diff --git a/libs/tonemap/Android.bp b/libs/tonemap/Android.bp
index dc55586..37c9824 100644
--- a/libs/tonemap/Android.bp
+++ b/libs/tonemap/Android.bp
@@ -29,6 +29,7 @@
shared_libs: [
"android.hardware.graphics.common-V3-ndk",
+ "android.hardware.graphics.composer3-V1-ndk",
"liblog",
"libnativewindow",
],
diff --git a/libs/tonemap/include/tonemap/tonemap.h b/libs/tonemap/include/tonemap/tonemap.h
index c51016d..852fc87 100644
--- a/libs/tonemap/include/tonemap/tonemap.h
+++ b/libs/tonemap/include/tonemap/tonemap.h
@@ -17,6 +17,7 @@
#pragma once
#include <aidl/android/hardware/graphics/common/Dataspace.h>
+#include <aidl/android/hardware/graphics/composer3/RenderIntent.h>
#include <android/hardware_buffer.h>
#include <math/vec3.h>
@@ -41,7 +42,7 @@
// Describes metadata which may be used for constructing the shader uniforms.
// This metadata should not be used for manipulating the source code of the shader program directly,
-// as otherwise caching by other system of these shaders may break.
+// as otherwise caching by other parts of the system using these shaders may break.
struct Metadata {
// The maximum luminance of the display in nits
float displayMaxLuminance = 0.0;
@@ -61,6 +62,17 @@
// texture that does not have associated metadata. As such, implementations
// must support nullptr.
AHardwareBuffer* buffer = nullptr;
+
+ // RenderIntent of the destination display.
+ // Non-colorimetric render-intents may be defined in order to take advantage of the full display
+ // gamut. Various contrast-enhancement mechanisms may be employed on SDR content as a result,
+ // which means that HDR content may need to be compensated in order to achieve correct blending
+ // behavior. This default is effectively optional - the display render intent may not be
+ // available to clients such as HWUI which are display-agnostic. For those clients, tone-map
+ // colorimetric may be assumed so that the luminance range may be converted to the correct range
+ // based on the output dataspace.
+ aidl::android::hardware::graphics::composer3::RenderIntent renderIntent =
+ aidl::android::hardware::graphics::composer3::RenderIntent::TONE_MAP_COLORIMETRIC;
};
// Utility class containing pre-processed conversions for a particular color
diff --git a/libs/tonemap/tests/Android.bp b/libs/tonemap/tests/Android.bp
index 26a1d79..58851b4 100644
--- a/libs/tonemap/tests/Android.bp
+++ b/libs/tonemap/tests/Android.bp
@@ -32,6 +32,7 @@
],
shared_libs: [
"android.hardware.graphics.common-V3-ndk",
+ "android.hardware.graphics.composer3-V1-ndk",
"libnativewindow",
],
static_libs: [
diff --git a/libs/ui/DeviceProductInfo.cpp b/libs/ui/DeviceProductInfo.cpp
index 4d6ce43..04d9d3c 100644
--- a/libs/ui/DeviceProductInfo.cpp
+++ b/libs/ui/DeviceProductInfo.cpp
@@ -57,7 +57,7 @@
}
void DeviceProductInfo::dump(std::string& result) const {
- StringAppendF(&result, "{name=%s, ", name.c_str());
+ StringAppendF(&result, "{name=\"%s\", ", name.c_str());
StringAppendF(&result, "manufacturerPnpId=%s, ", manufacturerPnpId.data());
StringAppendF(&result, "productId=%s, ", productId.c_str());
diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp
index 1a42642..4f950b8 100644
--- a/libs/ui/Gralloc4.cpp
+++ b/libs/ui/Gralloc4.cpp
@@ -22,6 +22,7 @@
#include <aidlcommonsupport/NativeHandle.h>
#include <android/binder_enums.h>
#include <android/binder_manager.h>
+#include <gralloctypes/Gralloc4.h>
#include <hidl/ServiceManagement.h>
#include <hwbinder/IPCThreadState.h>
#include <ui/Gralloc4.h>
@@ -358,20 +359,19 @@
if (!gralloc4::isStandardPlaneLayoutComponentType(planeLayoutComponent.type)) {
continue;
}
- if (0 != planeLayoutComponent.offsetInBits % 8) {
- unlock(bufferHandle);
- return BAD_VALUE;
- }
- uint8_t* tmpData = static_cast<uint8_t*>(data) + planeLayout.offsetInBytes +
- (planeLayoutComponent.offsetInBits / 8);
+ uint8_t* tmpData = static_cast<uint8_t*>(data) + planeLayout.offsetInBytes;
+
+ // Note that `offsetInBits` may not be a multiple of 8 for packed formats (e.g. P010)
+ // but we still want to point to the start of the first byte.
+ tmpData += (planeLayoutComponent.offsetInBits / 8);
+
uint64_t sampleIncrementInBytes;
auto type = static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value);
switch (type) {
case PlaneLayoutComponentType::Y:
- if ((ycbcr.y != nullptr) || (planeLayoutComponent.sizeInBits != 8) ||
- (planeLayout.sampleIncrementInBits != 8)) {
+ if ((ycbcr.y != nullptr) || (planeLayout.sampleIncrementInBits % 8 != 0)) {
unlock(bufferHandle);
return BAD_VALUE;
}
@@ -387,7 +387,8 @@
}
sampleIncrementInBytes = planeLayout.sampleIncrementInBits / 8;
- if ((sampleIncrementInBytes != 1) && (sampleIncrementInBytes != 2)) {
+ if ((sampleIncrementInBytes != 1) && (sampleIncrementInBytes != 2) &&
+ (sampleIncrementInBytes != 4)) {
unlock(bufferHandle);
return BAD_VALUE;
}
@@ -524,6 +525,37 @@
return decodeFunction(vec, outMetadata);
}
+template <class T>
+status_t Gralloc4Mapper::set(buffer_handle_t bufferHandle, const MetadataType& metadataType,
+ const T& metadata, EncodeFunction<T> encodeFunction) const {
+ hidl_vec<uint8_t> encodedMetadata;
+ if (const status_t status = encodeFunction(metadata, &encodedMetadata); status != OK) {
+ ALOGE("Encoding metadata(%s) failed with %d", metadataType.name.c_str(), status);
+ return status;
+ }
+ hidl_vec<uint8_t> vec;
+ auto ret =
+ mMapper->set(const_cast<native_handle_t*>(bufferHandle), metadataType, encodedMetadata);
+
+ const Error error = ret.withDefault(kTransactionError);
+ switch (error) {
+ case Error::BAD_DESCRIPTOR:
+ case Error::BAD_BUFFER:
+ case Error::BAD_VALUE:
+ case Error::NO_RESOURCES:
+ ALOGE("set(%s, %" PRIu64 ", ...) failed with %d", metadataType.name.c_str(),
+ metadataType.value, error);
+ break;
+ // It is not an error to attempt to set metadata that a particular gralloc implementation
+ // happens to not support.
+ case Error::UNSUPPORTED:
+ case Error::NONE:
+ break;
+ }
+
+ return static_cast<status_t>(error);
+}
+
status_t Gralloc4Mapper::getBufferId(buffer_handle_t bufferHandle, uint64_t* outBufferId) const {
return get(bufferHandle, gralloc4::MetadataType_BufferId, gralloc4::decodeBufferId,
outBufferId);
@@ -673,6 +705,12 @@
return NO_ERROR;
}
+status_t Gralloc4Mapper::setDataspace(buffer_handle_t bufferHandle, ui::Dataspace dataspace) const {
+ return set(bufferHandle, gralloc4::MetadataType_Dataspace,
+ static_cast<aidl::android::hardware::graphics::common::Dataspace>(dataspace),
+ gralloc4::encodeDataspace);
+}
+
status_t Gralloc4Mapper::getBlendMode(buffer_handle_t bufferHandle,
ui::BlendMode* outBlendMode) const {
return get(bufferHandle, gralloc4::MetadataType_BlendMode, gralloc4::decodeBlendMode,
@@ -685,24 +723,47 @@
outSmpte2086);
}
+status_t Gralloc4Mapper::setSmpte2086(buffer_handle_t bufferHandle,
+ std::optional<ui::Smpte2086> smpte2086) const {
+ return set(bufferHandle, gralloc4::MetadataType_Smpte2086, smpte2086,
+ gralloc4::encodeSmpte2086);
+}
+
status_t Gralloc4Mapper::getCta861_3(buffer_handle_t bufferHandle,
std::optional<ui::Cta861_3>* outCta861_3) const {
return get(bufferHandle, gralloc4::MetadataType_Cta861_3, gralloc4::decodeCta861_3,
outCta861_3);
}
+status_t Gralloc4Mapper::setCta861_3(buffer_handle_t bufferHandle,
+ std::optional<ui::Cta861_3> cta861_3) const {
+ return set(bufferHandle, gralloc4::MetadataType_Cta861_3, cta861_3, gralloc4::encodeCta861_3);
+}
+
status_t Gralloc4Mapper::getSmpte2094_40(
buffer_handle_t bufferHandle, std::optional<std::vector<uint8_t>>* outSmpte2094_40) const {
return get(bufferHandle, gralloc4::MetadataType_Smpte2094_40, gralloc4::decodeSmpte2094_40,
outSmpte2094_40);
}
+status_t Gralloc4Mapper::setSmpte2094_40(buffer_handle_t bufferHandle,
+ std::optional<std::vector<uint8_t>> smpte2094_40) const {
+ return set(bufferHandle, gralloc4::MetadataType_Smpte2094_40, smpte2094_40,
+ gralloc4::encodeSmpte2094_40);
+}
+
status_t Gralloc4Mapper::getSmpte2094_10(
buffer_handle_t bufferHandle, std::optional<std::vector<uint8_t>>* outSmpte2094_10) const {
return get(bufferHandle, gralloc4::MetadataType_Smpte2094_10, gralloc4::decodeSmpte2094_10,
outSmpte2094_10);
}
+status_t Gralloc4Mapper::setSmpte2094_10(buffer_handle_t bufferHandle,
+ std::optional<std::vector<uint8_t>> smpte2094_10) const {
+ return set(bufferHandle, gralloc4::MetadataType_Smpte2094_10, smpte2094_10,
+ gralloc4::encodeSmpte2094_10);
+}
+
template <class T>
status_t Gralloc4Mapper::getDefault(uint32_t width, uint32_t height, PixelFormat format,
uint32_t layerCount, uint64_t usage,
@@ -1132,10 +1193,6 @@
Gralloc4Allocator::Gralloc4Allocator(const Gralloc4Mapper& mapper) : mMapper(mapper) {
mAllocator = IAllocator::getService();
- if (mAllocator == nullptr) {
- ALOGW("allocator 4.x is not supported");
- return;
- }
if (__builtin_available(android 31, *)) {
if (hasIAllocatorAidl()) {
mAidlAllocator = AidlIAllocator::fromBinder(ndk::SpAIBinder(
@@ -1143,10 +1200,14 @@
ALOGE_IF(!mAidlAllocator, "AIDL IAllocator declared but failed to get service");
}
}
+ if (mAllocator == nullptr && mAidlAllocator == nullptr) {
+ ALOGW("allocator 4.x is not supported");
+ return;
+ }
}
bool Gralloc4Allocator::isLoaded() const {
- return mAllocator != nullptr;
+ return mAllocator != nullptr || mAidlAllocator != nullptr;
}
std::string Gralloc4Allocator::dumpDebugInfo(bool less) const {
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index 82d6cd5..a98e697 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -281,6 +281,10 @@
return mMapper->getDataspace(bufferHandle, outDataspace);
}
+status_t GraphicBufferMapper::setDataspace(buffer_handle_t bufferHandle, ui::Dataspace dataspace) {
+ return mMapper->setDataspace(bufferHandle, dataspace);
+}
+
status_t GraphicBufferMapper::getBlendMode(buffer_handle_t bufferHandle,
ui::BlendMode* outBlendMode) {
return mMapper->getBlendMode(bufferHandle, outBlendMode);
@@ -291,21 +295,41 @@
return mMapper->getSmpte2086(bufferHandle, outSmpte2086);
}
+status_t GraphicBufferMapper::setSmpte2086(buffer_handle_t bufferHandle,
+ std::optional<ui::Smpte2086> smpte2086) {
+ return mMapper->setSmpte2086(bufferHandle, smpte2086);
+}
+
status_t GraphicBufferMapper::getCta861_3(buffer_handle_t bufferHandle,
std::optional<ui::Cta861_3>* outCta861_3) {
return mMapper->getCta861_3(bufferHandle, outCta861_3);
}
+status_t GraphicBufferMapper::setCta861_3(buffer_handle_t bufferHandle,
+ std::optional<ui::Cta861_3> cta861_3) {
+ return mMapper->setCta861_3(bufferHandle, cta861_3);
+}
+
status_t GraphicBufferMapper::getSmpte2094_40(
buffer_handle_t bufferHandle, std::optional<std::vector<uint8_t>>* outSmpte2094_40) {
return mMapper->getSmpte2094_40(bufferHandle, outSmpte2094_40);
}
+status_t GraphicBufferMapper::setSmpte2094_40(buffer_handle_t bufferHandle,
+ std::optional<std::vector<uint8_t>> smpte2094_40) {
+ return mMapper->setSmpte2094_40(bufferHandle, smpte2094_40);
+}
+
status_t GraphicBufferMapper::getSmpte2094_10(
buffer_handle_t bufferHandle, std::optional<std::vector<uint8_t>>* outSmpte2094_10) {
return mMapper->getSmpte2094_10(bufferHandle, outSmpte2094_10);
}
+status_t GraphicBufferMapper::setSmpte2094_10(buffer_handle_t bufferHandle,
+ std::optional<std::vector<uint8_t>> smpte2094_10) {
+ return mMapper->setSmpte2094_10(bufferHandle, smpte2094_10);
+}
+
status_t GraphicBufferMapper::getDefaultPixelFormatFourCC(uint32_t width, uint32_t height,
PixelFormat format, uint32_t layerCount,
uint64_t usage,
diff --git a/libs/ui/include/ui/Gralloc.h b/libs/ui/include/ui/Gralloc.h
index 753b0a6..6101d4b 100644
--- a/libs/ui/include/ui/Gralloc.h
+++ b/libs/ui/include/ui/Gralloc.h
@@ -161,6 +161,10 @@
ui::Dataspace* /*outDataspace*/) const {
return INVALID_OPERATION;
}
+ virtual status_t setDataspace(buffer_handle_t /*bufferHandle*/,
+ ui::Dataspace /*dataspace*/) const {
+ return INVALID_OPERATION;
+ }
virtual status_t getBlendMode(buffer_handle_t /*bufferHandle*/,
ui::BlendMode* /*outBlendMode*/) const {
return INVALID_OPERATION;
@@ -169,21 +173,36 @@
std::optional<ui::Smpte2086>* /*outSmpte2086*/) const {
return INVALID_OPERATION;
}
+ virtual status_t setSmpte2086(buffer_handle_t /*bufferHandle*/,
+ std::optional<ui::Smpte2086> /*smpte2086*/) const {
+ return INVALID_OPERATION;
+ }
virtual status_t getCta861_3(buffer_handle_t /*bufferHandle*/,
std::optional<ui::Cta861_3>* /*outCta861_3*/) const {
return INVALID_OPERATION;
}
+ virtual status_t setCta861_3(buffer_handle_t /*bufferHandle*/,
+ std::optional<ui::Cta861_3> /*cta861_3*/) const {
+ return INVALID_OPERATION;
+ }
virtual status_t getSmpte2094_40(
buffer_handle_t /*bufferHandle*/,
std::optional<std::vector<uint8_t>>* /*outSmpte2094_40*/) const {
return INVALID_OPERATION;
}
+ virtual status_t setSmpte2094_40(buffer_handle_t /*bufferHandle*/,
+ std::optional<std::vector<uint8_t>> /*smpte2094_40*/) const {
+ return INVALID_OPERATION;
+ }
virtual status_t getSmpte2094_10(
buffer_handle_t /*bufferHandle*/,
std::optional<std::vector<uint8_t>>* /*outSmpte2094_10*/) const {
return INVALID_OPERATION;
}
-
+ virtual status_t setSmpte2094_10(buffer_handle_t /*bufferHandle*/,
+ std::optional<std::vector<uint8_t>> /*smpte2094_10*/) const {
+ return INVALID_OPERATION;
+ }
virtual status_t getDefaultPixelFormatFourCC(uint32_t /*width*/, uint32_t /*height*/,
PixelFormat /*format*/, uint32_t /*layerCount*/,
uint64_t /*usage*/,
diff --git a/libs/ui/include/ui/Gralloc4.h b/libs/ui/include/ui/Gralloc4.h
index fe38709..cf023c9 100644
--- a/libs/ui/include/ui/Gralloc4.h
+++ b/libs/ui/include/ui/Gralloc4.h
@@ -102,16 +102,24 @@
status_t getPlaneLayouts(buffer_handle_t bufferHandle,
std::vector<ui::PlaneLayout>* outPlaneLayouts) const override;
status_t getDataspace(buffer_handle_t bufferHandle, ui::Dataspace* outDataspace) const override;
+ status_t setDataspace(buffer_handle_t bufferHandle, ui::Dataspace dataspace) const override;
status_t getBlendMode(buffer_handle_t bufferHandle, ui::BlendMode* outBlendMode) const override;
status_t getSmpte2086(buffer_handle_t bufferHandle,
std::optional<ui::Smpte2086>* outSmpte2086) const override;
+ status_t setSmpte2086(buffer_handle_t bufferHandle,
+ std::optional<ui::Smpte2086> smpte2086) const override;
status_t getCta861_3(buffer_handle_t bufferHandle,
std::optional<ui::Cta861_3>* outCta861_3) const override;
+ status_t setCta861_3(buffer_handle_t bufferHandle,
+ std::optional<ui::Cta861_3> cta861_3) const override;
status_t getSmpte2094_40(buffer_handle_t bufferHandle,
std::optional<std::vector<uint8_t>>* outSmpte2094_40) const override;
+ status_t setSmpte2094_40(buffer_handle_t bufferHandle,
+ std::optional<std::vector<uint8_t>> smpte2094_40) const override;
status_t getSmpte2094_10(buffer_handle_t bufferHandle,
std::optional<std::vector<uint8_t>>* outSmpte2094_10) const override;
-
+ status_t setSmpte2094_10(buffer_handle_t bufferHandle,
+ std::optional<std::vector<uint8_t>> smpte2094_10) const override;
status_t getDefaultPixelFormatFourCC(uint32_t width, uint32_t height, PixelFormat format,
uint32_t layerCount, uint64_t usage,
uint32_t* outPixelFormatFourCC) const override;
@@ -157,6 +165,8 @@
template <class T>
using DecodeFunction = status_t (*)(const hardware::hidl_vec<uint8_t>& input, T* output);
+ template <class T>
+ using EncodeFunction = status_t (*)(const T& input, hardware::hidl_vec<uint8_t>* output);
template <class T>
status_t get(
@@ -165,6 +175,12 @@
DecodeFunction<T> decodeFunction, T* outMetadata) const;
template <class T>
+ status_t set(
+ buffer_handle_t bufferHandle,
+ const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType& metadataType,
+ const T& metadata, EncodeFunction<T> encodeFunction) const;
+
+ template <class T>
status_t getDefault(
uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount,
uint64_t usage,
diff --git a/libs/ui/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h
index 257c155..507fa35 100644
--- a/libs/ui/include/ui/GraphicBufferMapper.h
+++ b/libs/ui/include/ui/GraphicBufferMapper.h
@@ -121,13 +121,20 @@
status_t getPlaneLayouts(buffer_handle_t bufferHandle,
std::vector<ui::PlaneLayout>* outPlaneLayouts);
status_t getDataspace(buffer_handle_t bufferHandle, ui::Dataspace* outDataspace);
+ status_t setDataspace(buffer_handle_t bufferHandle, ui::Dataspace dataspace);
status_t getBlendMode(buffer_handle_t bufferHandle, ui::BlendMode* outBlendMode);
status_t getSmpte2086(buffer_handle_t bufferHandle, std::optional<ui::Smpte2086>* outSmpte2086);
+ status_t setSmpte2086(buffer_handle_t bufferHandle, std::optional<ui::Smpte2086> smpte2086);
status_t getCta861_3(buffer_handle_t bufferHandle, std::optional<ui::Cta861_3>* outCta861_3);
+ status_t setCta861_3(buffer_handle_t bufferHandle, std::optional<ui::Cta861_3> cta861_3);
status_t getSmpte2094_40(buffer_handle_t bufferHandle,
std::optional<std::vector<uint8_t>>* outSmpte2094_40);
+ status_t setSmpte2094_40(buffer_handle_t bufferHandle,
+ std::optional<std::vector<uint8_t>> smpte2094_40);
status_t getSmpte2094_10(buffer_handle_t bufferHandle,
std::optional<std::vector<uint8_t>>* outSmpte2094_10);
+ status_t setSmpte2094_10(buffer_handle_t bufferHandle,
+ std::optional<std::vector<uint8_t>> smpte2094_10);
/**
* Gets the default metadata for a gralloc buffer allocated with the given parameters.
diff --git a/libs/ui/include/ui/GraphicTypes.h b/libs/ui/include/ui/GraphicTypes.h
index 4bdacb0..8661c36 100644
--- a/libs/ui/include/ui/GraphicTypes.h
+++ b/libs/ui/include/ui/GraphicTypes.h
@@ -62,5 +62,23 @@
using Compression = aidl::android::hardware::graphics::common::Compression;
using Interlaced = aidl::android::hardware::graphics::common::Interlaced;
+inline aidl::android::hardware::graphics::common::XyColor translate(const android_xy_color& color) {
+ return aidl::android::hardware::graphics::common::XyColor{.x = color.x, .y = color.y};
+}
+
+inline Smpte2086 translate(const android_smpte2086_metadata& metadata) {
+ return Smpte2086{.primaryRed = translate(metadata.displayPrimaryRed),
+ .primaryGreen = translate(metadata.displayPrimaryGreen),
+ .primaryBlue = translate(metadata.displayPrimaryBlue),
+ .whitePoint = translate(metadata.whitePoint),
+ .maxLuminance = metadata.maxLuminance,
+ .minLuminance = metadata.minLuminance};
+}
+
+inline Cta861_3 translate(const android_cta861_3_metadata& metadata) {
+ return Cta861_3{.maxContentLightLevel = metadata.maxContentLightLevel,
+ .maxFrameAverageLightLevel = metadata.maxFrameAverageLightLevel};
+}
+
} // namespace ui
} // namespace android
diff --git a/libs/ui/include/ui/Size.h b/libs/ui/include/ui/Size.h
index ecc192d..bdcbd56 100644
--- a/libs/ui/include/ui/Size.h
+++ b/libs/ui/include/ui/Size.h
@@ -23,6 +23,8 @@
#include <type_traits>
#include <utility>
+#include <ui/Rotation.h>
+
namespace android::ui {
// A simple value type representing a two-dimensional size.
@@ -61,6 +63,16 @@
set(Size(w, h));
}
+ // Applies a rotation onto the size
+ void rotate(Rotation rotation) {
+ if (rotation == ROTATION_90 || rotation == ROTATION_270) {
+ transpose();
+ }
+ }
+
+ // Swaps the width and height, emulating a 90 degree rotation.
+ void transpose() { std::swap(width, height); }
+
// Sets the value to kInvalidSize
void makeInvalid();
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 22fbf45..831b64d 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -114,7 +114,6 @@
],
shared_libs: [
"libbinder",
- "libgui",
"liblog",
"libui",
"libutils",
diff --git a/libs/ui/tests/GraphicBufferOverBinder_test.cpp b/libs/ui/tests/GraphicBufferOverBinder_test.cpp
index 126a945..4c9d574 100644
--- a/libs/ui/tests/GraphicBufferOverBinder_test.cpp
+++ b/libs/ui/tests/GraphicBufferOverBinder_test.cpp
@@ -20,9 +20,6 @@
#include <binder/Parcel.h>
#include <binder/ProcessState.h>
#include <gtest/gtest.h>
-#include <gui/BufferQueue.h>
-#include <gui/IGraphicBufferConsumer.h>
-#include <gui/IGraphicBufferProducer.h>
#include <ui/GraphicBuffer.h>
#include <utils/Log.h>
diff --git a/libs/ui/tests/Size_test.cpp b/libs/ui/tests/Size_test.cpp
index acef47f..0a236e6 100644
--- a/libs/ui/tests/Size_test.cpp
+++ b/libs/ui/tests/Size_test.cpp
@@ -61,6 +61,38 @@
EXPECT_FALSE(Size(1, 1) < Size(1, 1));
}
+TEST(SizeTest, Transpose) {
+ Size s(123, 456);
+ s.transpose();
+ EXPECT_EQ(s, Size(456, 123));
+}
+
+TEST(SizeTest, Rotate) {
+ {
+ Size s(123, 456);
+ s.rotate(Rotation::Rotation0);
+ EXPECT_EQ(s, Size(123, 456));
+ }
+
+ {
+ Size s(123, 456);
+ s.rotate(Rotation::Rotation90);
+ EXPECT_EQ(s, Size(456, 123));
+ }
+
+ {
+ Size s(123, 456);
+ s.rotate(Rotation::Rotation180);
+ EXPECT_EQ(s, Size(123, 456));
+ }
+
+ {
+ Size s(123, 456);
+ s.rotate(Rotation::Rotation270);
+ EXPECT_EQ(s, Size(456, 123));
+ }
+}
+
TEST(SizeTest, ValidAndEmpty) {
{
Size s;
diff --git a/libs/vr/libbroadcastring/Android.bp b/libs/vr/libbroadcastring/Android.bp
index d4538f1..fa449ae 100644
--- a/libs/vr/libbroadcastring/Android.bp
+++ b/libs/vr/libbroadcastring/Android.bp
@@ -9,7 +9,7 @@
cc_library_static {
name: "libbroadcastring",
- clang: true,
+
cflags: [
"-Wall",
"-Wextra",
diff --git a/services/gpuservice/gpuwork/bpfprogs/gpu_work.c b/services/gpuservice/gpuwork/bpfprogs/gpu_work.c
index c8e79a2..95cfae7 100644
--- a/services/gpuservice/gpuwork/bpfprogs/gpu_work.c
+++ b/services/gpuservice/gpuwork/bpfprogs/gpu_work.c
@@ -71,11 +71,14 @@
//
// The |total_active_duration_ns| must be set to the approximate total amount of
// time the GPU spent running work for |uid| within the period, without
-// "double-counting" parallel GPU work on the same GPU for the same |uid|. "GPU
-// work" should correspond to the "GPU slices" shown in the AGI (Android GPU
+// "double-counting" parallel GPU work on the same GPU for the same |uid|. Note
+// that even if the parallel GPU work was submitted from several different
+// processes (i.e. different PIDs) with the same UID, this overlapping work must
+// not be double-counted, as it still came from a single |uid|. "GPU work"
+// should correspond to the "GPU slices" shown in the AGI (Android GPU
// Inspector) tool, and so should include work such as fragment and non-fragment
// work/shaders running on the shader cores of the GPU. For example, given the
-// following:
+// following for a single |uid|:
// - A period has:
// - |start_time_ns|: 100,000,000 ns
// - |end_time_ns|: 800,000,000 ns
@@ -99,16 +102,20 @@
// - from 600,000,000 ns to 700,000,000 ns, giving a duration of 100,000,000 ns
// (GPU work D)
//
-// Thus, the |total_active_duration_ns| is the sum of the (non-overlapping)
-// durations. Drivers may not have efficient access to the exact start and end
-// times of all GPU work, as shown above, but drivers should try to
-// approximate/aggregate the value of |total_active_duration_ns| as accurately
-// as possible within the limitations of the hardware, without double-counting
-// parallel GPU work for the same |uid|. The |total_active_duration_ns| value
-// must be less than or equal to the period duration (|end_time_ns| -
-// |start_time_ns|); if the aggregation approach might violate this requirement
-// then the driver must clamp |total_active_duration_ns| to be at most the
-// period duration.
+// Thus, the |total_active_duration_ns| is the sum of these two
+// (non-overlapping) durations. Drivers may not have efficient access to the
+// exact start and end times of all GPU work, as shown above, but drivers should
+// try to approximate/aggregate the value of |total_active_duration_ns| as
+// accurately as possible within the limitations of the hardware, without
+// double-counting parallel GPU work for the same |uid|. The
+// |total_active_duration_ns| value must be less than or equal to the period
+// duration (|end_time_ns| - |start_time_ns|); if the aggregation approach might
+// violate this requirement then the driver must clamp
+// |total_active_duration_ns| to be at most the period duration.
+//
+// Protected mode: protected GPU work must not be reported. Periods must be
+// emitted, and the |total_active_duration_ns| value set, as if the protected
+// GPU work did not occur.
//
// Note that the above description allows for a certain amount of flexibility in
// how the driver tracks periods and emits the events. We list a few examples of
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index ed9bfd2..41878e3 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -58,6 +58,7 @@
srcs: [
"InputClassifier.cpp",
"InputCommonConverter.cpp",
+ "PreferStylusOverTouchBlocker.cpp",
"UnwantedInteractionBlocker.cpp",
"InputManager.cpp",
],
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index 3a4b6c5..2a3924b 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -202,9 +202,11 @@
coords += "}";
}
return StringPrintf("NotifyMotionArgs(id=%" PRId32 ", eventTime=%" PRId64 ", deviceId=%" PRId32
- ", source=%s, action=%s, pointerCount=%" PRIu32 " pointers=%s)",
+ ", source=%s, action=%s, pointerCount=%" PRIu32
+ " pointers=%s, flags=0x%08x)",
id, eventTime, deviceId, inputEventSourceToString(source).c_str(),
- MotionEvent::actionToString(action).c_str(), pointerCount, coords.c_str());
+ MotionEvent::actionToString(action).c_str(), pointerCount, coords.c_str(),
+ flags);
}
void NotifyMotionArgs::notify(InputListenerInterface& listener) const {
diff --git a/services/inputflinger/PreferStylusOverTouchBlocker.cpp b/services/inputflinger/PreferStylusOverTouchBlocker.cpp
new file mode 100644
index 0000000..beec2e1
--- /dev/null
+++ b/services/inputflinger/PreferStylusOverTouchBlocker.cpp
@@ -0,0 +1,216 @@
+/*
+ * 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 "PreferStylusOverTouchBlocker.h"
+#include <input/PrintTools.h>
+
+namespace android {
+
+static std::pair<bool, bool> checkToolType(const NotifyMotionArgs& args) {
+ bool hasStylus = false;
+ bool hasTouch = false;
+ for (size_t i = 0; i < args.pointerCount; i++) {
+ // Make sure we are canceling stylus pointers
+ const int32_t toolType = args.pointerProperties[i].toolType;
+ if (toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS ||
+ toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
+ hasStylus = true;
+ }
+ if (toolType == AMOTION_EVENT_TOOL_TYPE_FINGER) {
+ hasTouch = true;
+ }
+ }
+ return std::make_pair(hasTouch, hasStylus);
+}
+
+/**
+ * Intersect two sets in-place, storing the result in 'set1'.
+ * Find elements in set1 that are not present in set2 and delete them,
+ * relying on the fact that the two sets are ordered.
+ */
+template <typename T>
+static void intersectInPlace(std::set<T>& set1, const std::set<T>& set2) {
+ typename std::set<T>::iterator it1 = set1.begin();
+ typename std::set<T>::const_iterator it2 = set2.begin();
+ while (it1 != set1.end() && it2 != set2.end()) {
+ const T& element1 = *it1;
+ const T& element2 = *it2;
+ if (element1 < element2) {
+ // This element is not present in set2. Remove it from set1.
+ it1 = set1.erase(it1);
+ continue;
+ }
+ if (element2 < element1) {
+ it2++;
+ }
+ if (element1 == element2) {
+ it1++;
+ it2++;
+ }
+ }
+ // Remove the rest of the elements in set1 because set2 is already exhausted.
+ set1.erase(it1, set1.end());
+}
+
+/**
+ * Same as above, but prune a map
+ */
+template <typename K, class V>
+static void intersectInPlace(std::map<K, V>& map, const std::set<K>& set2) {
+ typename std::map<K, V>::iterator it1 = map.begin();
+ typename std::set<K>::const_iterator it2 = set2.begin();
+ while (it1 != map.end() && it2 != set2.end()) {
+ const auto& [key, _] = *it1;
+ const K& element2 = *it2;
+ if (key < element2) {
+ // This element is not present in set2. Remove it from map.
+ it1 = map.erase(it1);
+ continue;
+ }
+ if (element2 < key) {
+ it2++;
+ }
+ if (key == element2) {
+ it1++;
+ it2++;
+ }
+ }
+ // Remove the rest of the elements in map because set2 is already exhausted.
+ map.erase(it1, map.end());
+}
+
+// -------------------------------- PreferStylusOverTouchBlocker -----------------------------------
+
+std::vector<NotifyMotionArgs> PreferStylusOverTouchBlocker::processMotion(
+ const NotifyMotionArgs& args) {
+ const auto [hasTouch, hasStylus] = checkToolType(args);
+ const bool isUpOrCancel =
+ args.action == AMOTION_EVENT_ACTION_UP || args.action == AMOTION_EVENT_ACTION_CANCEL;
+
+ if (hasTouch && hasStylus) {
+ mDevicesWithMixedToolType.insert(args.deviceId);
+ }
+ // Handle the case where mixed touch and stylus pointers are reported. Add this device to the
+ // ignore list, since it clearly supports simultaneous touch and stylus.
+ if (mDevicesWithMixedToolType.find(args.deviceId) != mDevicesWithMixedToolType.end()) {
+ // This event comes from device with mixed stylus and touch event. Ignore this device.
+ if (mCanceledDevices.find(args.deviceId) != mCanceledDevices.end()) {
+ // If we started to cancel events from this device, continue to do so to keep
+ // the stream consistent. It should happen at most once per "mixed" device.
+ if (isUpOrCancel) {
+ mCanceledDevices.erase(args.deviceId);
+ mLastTouchEvents.erase(args.deviceId);
+ }
+ return {};
+ }
+ return {args};
+ }
+
+ const bool isStylusEvent = hasStylus;
+ const bool isDown = args.action == AMOTION_EVENT_ACTION_DOWN;
+
+ if (isStylusEvent) {
+ if (isDown) {
+ // Reject all touch while stylus is down
+ mActiveStyli.insert(args.deviceId);
+
+ // Cancel all current touch!
+ std::vector<NotifyMotionArgs> result;
+ for (auto& [deviceId, lastTouchEvent] : mLastTouchEvents) {
+ if (mCanceledDevices.find(deviceId) != mCanceledDevices.end()) {
+ // Already canceled, go to next one.
+ continue;
+ }
+ // Not yet canceled. Cancel it.
+ lastTouchEvent.action = AMOTION_EVENT_ACTION_CANCEL;
+ lastTouchEvent.flags |= AMOTION_EVENT_FLAG_CANCELED;
+ lastTouchEvent.eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ result.push_back(lastTouchEvent);
+ mCanceledDevices.insert(deviceId);
+ }
+ result.push_back(args);
+ return result;
+ }
+ if (isUpOrCancel) {
+ mActiveStyli.erase(args.deviceId);
+ }
+ // Never drop stylus events
+ return {args};
+ }
+
+ const bool isTouchEvent = hasTouch;
+ if (isTouchEvent) {
+ // Suppress the current gesture if any stylus is still down
+ if (!mActiveStyli.empty()) {
+ mCanceledDevices.insert(args.deviceId);
+ }
+
+ const bool shouldDrop = mCanceledDevices.find(args.deviceId) != mCanceledDevices.end();
+ if (isUpOrCancel) {
+ mCanceledDevices.erase(args.deviceId);
+ mLastTouchEvents.erase(args.deviceId);
+ }
+
+ // If we already canceled the current gesture, then continue to drop events from it, even if
+ // the stylus has been lifted.
+ if (shouldDrop) {
+ return {};
+ }
+
+ if (!isUpOrCancel) {
+ mLastTouchEvents[args.deviceId] = args;
+ }
+ return {args};
+ }
+
+ // Not a touch or stylus event
+ return {args};
+}
+
+void PreferStylusOverTouchBlocker::notifyInputDevicesChanged(
+ const std::vector<InputDeviceInfo>& inputDevices) {
+ std::set<int32_t> presentDevices;
+ for (const InputDeviceInfo& device : inputDevices) {
+ presentDevices.insert(device.getId());
+ }
+ // Only keep the devices that are still present.
+ intersectInPlace(mDevicesWithMixedToolType, presentDevices);
+ intersectInPlace(mLastTouchEvents, presentDevices);
+ intersectInPlace(mCanceledDevices, presentDevices);
+ intersectInPlace(mActiveStyli, presentDevices);
+}
+
+void PreferStylusOverTouchBlocker::notifyDeviceReset(const NotifyDeviceResetArgs& args) {
+ mDevicesWithMixedToolType.erase(args.deviceId);
+ mLastTouchEvents.erase(args.deviceId);
+ mCanceledDevices.erase(args.deviceId);
+ mActiveStyli.erase(args.deviceId);
+}
+
+static std::string dumpArgs(const NotifyMotionArgs& args) {
+ return args.dump();
+}
+
+std::string PreferStylusOverTouchBlocker::dump() const {
+ std::string out;
+ out += "mActiveStyli: " + dumpSet(mActiveStyli) + "\n";
+ out += "mLastTouchEvents: " + dumpMap(mLastTouchEvents, constToString, dumpArgs) + "\n";
+ out += "mDevicesWithMixedToolType: " + dumpSet(mDevicesWithMixedToolType) + "\n";
+ out += "mCanceledDevices: " + dumpSet(mCanceledDevices) + "\n";
+ return out;
+}
+
+} // namespace android
diff --git a/services/inputflinger/PreferStylusOverTouchBlocker.h b/services/inputflinger/PreferStylusOverTouchBlocker.h
new file mode 100644
index 0000000..716dc4d
--- /dev/null
+++ b/services/inputflinger/PreferStylusOverTouchBlocker.h
@@ -0,0 +1,65 @@
+/*
+ * 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 <optional>
+#include <set>
+#include "InputListener.h"
+
+namespace android {
+
+/**
+ * When stylus is down, all touch is ignored.
+ * TODO(b/210159205): delete this when simultaneous stylus and touch is supported
+ */
+class PreferStylusOverTouchBlocker {
+public:
+ /**
+ * Process the provided event and emit 0 or more events that should be used instead of it.
+ * In the majority of cases, the returned result will just be the provided args (array with
+ * only 1 element), unmodified.
+ *
+ * If the gesture should be blocked, the returned result may be:
+ *
+ * a) An empty array, if the current event should just be ignored completely
+ * b) An array of N elements, containing N-1 events with ACTION_CANCEL and the current event.
+ *
+ * The returned result is intended to be reinjected into the original event stream in
+ * replacement of the incoming event.
+ */
+ std::vector<NotifyMotionArgs> processMotion(const NotifyMotionArgs& args);
+ std::string dump() const;
+
+ void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices);
+
+ void notifyDeviceReset(const NotifyDeviceResetArgs& args);
+
+private:
+ // Stores the device id's of styli that are currently down.
+ std::set<int32_t /*deviceId*/> mActiveStyli;
+ // For each device, store the last touch event as long as the touch is down. Upon liftoff,
+ // the entry is erased.
+ std::map<int32_t /*deviceId*/, NotifyMotionArgs> mLastTouchEvents;
+ // Device ids of devices for which the current touch gesture is canceled.
+ std::set<int32_t /*deviceId*/> mCanceledDevices;
+
+ // Device ids of input devices where we encountered simultaneous touch and stylus
+ // events. For these devices, we don't do any event processing (nothing is blocked or altered).
+ std::set<int32_t /*deviceId*/> mDevicesWithMixedToolType;
+};
+
+} // namespace android
\ No newline at end of file
diff --git a/services/inputflinger/UnwantedInteractionBlocker.cpp b/services/inputflinger/UnwantedInteractionBlocker.cpp
index 64dbb8c..b69e16a 100644
--- a/services/inputflinger/UnwantedInteractionBlocker.cpp
+++ b/services/inputflinger/UnwantedInteractionBlocker.cpp
@@ -44,7 +44,8 @@
}
static bool isFromTouchscreen(int32_t source) {
- return isFromSource(source, AINPUT_SOURCE_TOUCHSCREEN);
+ return isFromSource(source, AINPUT_SOURCE_TOUCHSCREEN) &&
+ !isFromSource(source, AINPUT_SOURCE_STYLUS);
}
static ::base::TimeTicks toChromeTimestamp(nsecs_t eventTime) {
@@ -367,6 +368,14 @@
}
void UnwantedInteractionBlocker::notifyMotion(const NotifyMotionArgs* args) {
+ const std::vector<NotifyMotionArgs> processedArgs =
+ mPreferStylusOverTouchBlocker.processMotion(*args);
+ for (const NotifyMotionArgs& loopArgs : processedArgs) {
+ notifyMotionInner(&loopArgs);
+ }
+}
+
+void UnwantedInteractionBlocker::notifyMotionInner(const NotifyMotionArgs* args) {
auto it = mPalmRejectors.find(args->deviceId);
const bool sendToPalmRejector = it != mPalmRejectors.end() && isFromTouchscreen(args->source);
if (!sendToPalmRejector) {
@@ -400,6 +409,7 @@
mPalmRejectors.emplace(args->deviceId, info);
}
mListener.notifyDeviceReset(args);
+ mPreferStylusOverTouchBlocker.notifyDeviceReset(*args);
}
void UnwantedInteractionBlocker::notifyPointerCaptureChanged(
@@ -436,10 +446,13 @@
auto const& [deviceId, _] = item;
return devicesToKeep.find(deviceId) == devicesToKeep.end();
});
+ mPreferStylusOverTouchBlocker.notifyInputDevicesChanged(inputDevices);
}
void UnwantedInteractionBlocker::dump(std::string& dump) {
dump += "UnwantedInteractionBlocker:\n";
+ dump += " mPreferStylusOverTouchBlocker:\n";
+ dump += addPrefix(mPreferStylusOverTouchBlocker.dump(), " ");
dump += StringPrintf(" mEnablePalmRejection: %s\n", toString(mEnablePalmRejection));
dump += StringPrintf(" isPalmRejectionEnabled (flag value): %s\n",
toString(isPalmRejectionEnabled()));
diff --git a/services/inputflinger/UnwantedInteractionBlocker.h b/services/inputflinger/UnwantedInteractionBlocker.h
index 14068fd..8a1cd72 100644
--- a/services/inputflinger/UnwantedInteractionBlocker.h
+++ b/services/inputflinger/UnwantedInteractionBlocker.h
@@ -23,6 +23,8 @@
#include "ui/events/ozone/evdev/touch_filter/neural_stylus_palm_detection_filter_util.h"
#include "ui/events/ozone/evdev/touch_filter/palm_detection_filter.h"
+#include "PreferStylusOverTouchBlocker.h"
+
namespace android {
// --- Functions for manipulation of event streams
@@ -88,9 +90,14 @@
InputListenerInterface& mListener;
const bool mEnablePalmRejection;
+ // When stylus is down, ignore touch
+ PreferStylusOverTouchBlocker mPreferStylusOverTouchBlocker;
+
// Detect and reject unwanted palms on screen
// Use a separate palm rejector for every touch device.
std::map<int32_t /*deviceId*/, PalmRejector> mPalmRejectors;
+ // TODO(b/210159205): delete this when simultaneous stylus and touch is supported
+ void notifyMotionInner(const NotifyMotionArgs* args);
};
class SlotState {
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index 9691ad8..32eec29 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -263,15 +263,15 @@
static void benchmarkNotifyMotion(benchmark::State& state) {
// Create dispatcher
sp<FakeInputDispatcherPolicy> fakePolicy = new FakeInputDispatcherPolicy();
- std::unique_ptr<InputDispatcher> dispatcher = std::make_unique<InputDispatcher>(fakePolicy);
- dispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
- dispatcher->start();
+ InputDispatcher dispatcher(fakePolicy);
+ dispatcher.setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
+ dispatcher.start();
// Create a window that will receive motion events
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window = new FakeWindowHandle(application, *dispatcher, "Fake Window");
+ sp<FakeWindowHandle> window = new FakeWindowHandle(application, dispatcher, "Fake Window");
- dispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+ dispatcher.setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
NotifyMotionArgs motionArgs = generateMotionArgs();
@@ -280,55 +280,79 @@
motionArgs.action = AMOTION_EVENT_ACTION_DOWN;
motionArgs.downTime = now();
motionArgs.eventTime = motionArgs.downTime;
- dispatcher->notifyMotion(&motionArgs);
+ dispatcher.notifyMotion(&motionArgs);
// Send ACTION_UP
motionArgs.action = AMOTION_EVENT_ACTION_UP;
motionArgs.eventTime = now();
- dispatcher->notifyMotion(&motionArgs);
+ dispatcher.notifyMotion(&motionArgs);
window->consumeEvent();
window->consumeEvent();
}
- dispatcher->stop();
+ dispatcher.stop();
}
static void benchmarkInjectMotion(benchmark::State& state) {
// Create dispatcher
sp<FakeInputDispatcherPolicy> fakePolicy = new FakeInputDispatcherPolicy();
- std::unique_ptr<InputDispatcher> dispatcher = std::make_unique<InputDispatcher>(fakePolicy);
- dispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
- dispatcher->start();
+ InputDispatcher dispatcher(fakePolicy);
+ dispatcher.setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
+ dispatcher.start();
// Create a window that will receive motion events
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window = new FakeWindowHandle(application, *dispatcher, "Fake Window");
+ sp<FakeWindowHandle> window = new FakeWindowHandle(application, dispatcher, "Fake Window");
- dispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+ dispatcher.setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
for (auto _ : state) {
MotionEvent event = generateMotionEvent();
// Send ACTION_DOWN
- dispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, INJECT_EVENT_TIMEOUT,
- POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
+ dispatcher.injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ InputEventInjectionSync::NONE, INJECT_EVENT_TIMEOUT,
+ POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
// Send ACTION_UP
event.setAction(AMOTION_EVENT_ACTION_UP);
- dispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, INJECT_EVENT_TIMEOUT,
- POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
+ dispatcher.injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ InputEventInjectionSync::NONE, INJECT_EVENT_TIMEOUT,
+ POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
window->consumeEvent();
window->consumeEvent();
}
- dispatcher->stop();
+ dispatcher.stop();
+}
+
+static void benchmarkOnWindowInfosChanged(benchmark::State& state) {
+ // Create dispatcher
+ sp<FakeInputDispatcherPolicy> fakePolicy = new FakeInputDispatcherPolicy();
+ InputDispatcher dispatcher(fakePolicy);
+ dispatcher.setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
+ dispatcher.start();
+
+ // Create a window
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window = new FakeWindowHandle(application, dispatcher, "Fake Window");
+
+ std::vector<gui::WindowInfo> windowInfos{*window->getInfo()};
+ gui::DisplayInfo info;
+ info.displayId = window->getInfo()->displayId;
+ std::vector<gui::DisplayInfo> displayInfos{info};
+
+ for (auto _ : state) {
+ dispatcher.onWindowInfosChanged(windowInfos, displayInfos);
+ dispatcher.onWindowInfosChanged({} /*windowInfos*/, {} /*displayInfos*/);
+ }
+ dispatcher.stop();
}
BENCHMARK(benchmarkNotifyMotion);
BENCHMARK(benchmarkInjectMotion);
+BENCHMARK(benchmarkOnWindowInfosChanged);
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index c8a3ccf..1cc4589 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -567,6 +567,17 @@
return !info.inputConfig.test(gui::WindowInfo::InputConfig::NOT_TOUCHABLE) && !info.isSpy();
}
+bool isWindowOwnedBy(const sp<WindowInfoHandle>& windowHandle, int32_t pid, int32_t uid) {
+ if (windowHandle == nullptr) {
+ return false;
+ }
+ const WindowInfo* windowInfo = windowHandle->getInfo();
+ if (pid == windowInfo->ownerPid && uid == windowInfo->ownerUid) {
+ return true;
+ }
+ return false;
+}
+
} // namespace
// --- InputDispatcher ---
@@ -2350,8 +2361,8 @@
*touchedWindow.windowHandle->getInfo()) ||
(touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) != 0;
})) {
- ALOGI("Dropping event because there is no touched window on display %d to receive it.",
- displayId);
+ ALOGI("Dropping event because there is no touched window on display %d to receive it: %s",
+ displayId, entry.getDescription().c_str());
injectionResult = InputEventInjectionResult::FAILED;
goto Failed;
}
@@ -4990,21 +5001,11 @@
toString(mInTouchMode), toString(inTouchMode), pid, uid, toString(hasPermission));
}
if (!hasPermission) {
- const sp<IBinder> focusedToken =
- mFocusResolver.getFocusedWindowToken(mFocusedDisplayId);
-
- // 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) {
- return false;
- }
- const sp<WindowInfoHandle> windowHandle = getWindowHandleLocked(focusedToken);
- if (windowHandle == nullptr) {
- return false;
- }
- const WindowInfo* windowInfo = windowHandle->getInfo();
- if (pid != windowInfo->ownerPid || uid != windowInfo->ownerUid) {
+ if (!focusedWindowIsOwnedByLocked(pid, uid) &&
+ !recentWindowsAreOwnedByLocked(pid, uid)) {
+ ALOGD("Touch mode switch rejected, caller (pid=%d, uid=%d) doesn't own the focused "
+ "window nor none of the previously interacted window",
+ pid, uid);
return false;
}
}
@@ -5022,6 +5023,24 @@
return true;
}
+bool InputDispatcher::focusedWindowIsOwnedByLocked(int32_t pid, int32_t uid) {
+ const sp<IBinder> focusedToken = mFocusResolver.getFocusedWindowToken(mFocusedDisplayId);
+ if (focusedToken == nullptr) {
+ return false;
+ }
+ sp<WindowInfoHandle> windowHandle = getWindowHandleLocked(focusedToken);
+ return isWindowOwnedBy(windowHandle, pid, uid);
+}
+
+bool InputDispatcher::recentWindowsAreOwnedByLocked(int32_t pid, int32_t uid) {
+ return std::find_if(mInteractionConnectionTokens.begin(), mInteractionConnectionTokens.end(),
+ [&](const sp<IBinder>& connectionToken) REQUIRES(mLock) {
+ const sp<WindowInfoHandle> windowHandle =
+ getWindowHandleLocked(connectionToken);
+ return isWindowOwnedBy(windowHandle, pid, uid);
+ }) != mInteractionConnectionTokens.end();
+}
+
void InputDispatcher::setMaximumObscuringOpacityForTouch(float opacity) {
if (opacity < 0 || opacity > 1) {
LOG_ALWAYS_FATAL("Maximum obscuring opacity for touch should be >= 0 and <= 1");
@@ -5121,28 +5140,54 @@
return true;
}
+/**
+ * Get the touched foreground window on the given display.
+ * Return null if there are no windows touched on that display, or if more than one foreground
+ * window is being touched.
+ */
+sp<WindowInfoHandle> InputDispatcher::findTouchedForegroundWindowLocked(int32_t displayId) const {
+ auto stateIt = mTouchStatesByDisplay.find(displayId);
+ if (stateIt == mTouchStatesByDisplay.end()) {
+ ALOGI("No touch state on display %" PRId32, displayId);
+ return nullptr;
+ }
+
+ const TouchState& state = stateIt->second;
+ sp<WindowInfoHandle> touchedForegroundWindow;
+ // If multiple foreground windows are touched, return nullptr
+ for (const TouchedWindow& window : state.windows) {
+ if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
+ if (touchedForegroundWindow != nullptr) {
+ ALOGI("Two or more foreground windows: %s and %s",
+ touchedForegroundWindow->getName().c_str(),
+ window.windowHandle->getName().c_str());
+ return nullptr;
+ }
+ touchedForegroundWindow = window.windowHandle;
+ }
+ }
+ return touchedForegroundWindow;
+}
+
// Binder call
-bool InputDispatcher::transferTouch(const sp<IBinder>& destChannelToken) {
+bool InputDispatcher::transferTouch(const sp<IBinder>& destChannelToken, int32_t displayId) {
sp<IBinder> fromToken;
{ // acquire lock
std::scoped_lock _l(mLock);
-
- auto it = std::find_if(mTouchStatesByDisplay.begin(), mTouchStatesByDisplay.end(),
- [](const auto& pair) { return pair.second.windows.size() == 1; });
- if (it == mTouchStatesByDisplay.end()) {
- ALOGW("Cannot transfer touch state because there is no exact window being touched");
- return false;
- }
- const int32_t displayId = it->first;
sp<WindowInfoHandle> toWindowHandle = getWindowHandleLocked(destChannelToken, displayId);
if (toWindowHandle == nullptr) {
- ALOGW("Could not find window associated with token=%p", destChannelToken.get());
+ ALOGW("Could not find window associated with token=%p on display %" PRId32,
+ destChannelToken.get(), displayId);
return false;
}
- TouchState& state = it->second;
- const TouchedWindow& touchedWindow = state.windows[0];
- fromToken = touchedWindow.windowHandle->getToken();
+ sp<WindowInfoHandle> from = findTouchedForegroundWindowLocked(displayId);
+ if (from == nullptr) {
+ ALOGE("Could not find a source window in %s for %p", __func__, destChannelToken.get());
+ return false;
+ }
+
+ fromToken = from->getToken();
} // release lock
return transferTouchFocus(fromToken, destChannelToken);
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 3c79c98..f3dac19 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -125,7 +125,7 @@
bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken,
bool isDragDrop = false) override;
- bool transferTouch(const sp<IBinder>& destChannelToken) override;
+ bool transferTouch(const sp<IBinder>& destChannelToken, int32_t displayId) override;
base::Result<std::unique_ptr<InputChannel>> createInputChannel(
const std::string& name) override;
@@ -245,6 +245,9 @@
std::vector<sp<android::gui::WindowInfoHandle>> findTouchedSpyWindowsAtLocked(
int32_t displayId, int32_t x, int32_t y, bool isStylus) const REQUIRES(mLock);
+ sp<android::gui::WindowInfoHandle> findTouchedForegroundWindowLocked(int32_t displayId) const
+ REQUIRES(mLock);
+
sp<Connection> getConnectionLocked(const sp<IBinder>& inputConnectionToken) const
REQUIRES(mLock);
@@ -433,7 +436,8 @@
// Dispatcher state at time of last ANR.
std::string mLastAnrState GUARDED_BY(mLock);
- // The connection tokens of the channels that the user last interacted, for debugging
+ // The connection tokens of the channels that the user last interacted (used for debugging and
+ // when switching touch mode state).
std::unordered_set<sp<IBinder>, StrongPointerHash<IBinder>> mInteractionConnectionTokens
GUARDED_BY(mLock);
void updateInteractionTokensLocked(const EventEntry& entry,
@@ -677,6 +681,10 @@
void traceOutboundQueueLength(const Connection& connection);
void traceWaitQueueLength(const Connection& connection);
+ // Check window ownership
+ bool focusedWindowIsOwnedByLocked(int32_t pid, int32_t uid) REQUIRES(mLock);
+ bool recentWindowsAreOwnedByLocked(int32_t pid, int32_t uid) REQUIRES(mLock);
+
sp<InputReporterInterface> mReporter;
};
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index 67e1b6f..d7bc5fb 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -155,7 +155,7 @@
*
* Return true on success, false if there was no on-going touch.
*/
- virtual bool transferTouch(const sp<IBinder>& destChannelToken) = 0;
+ virtual bool transferTouch(const sp<IBinder>& destChannelToken, int32_t displayId) = 0;
/**
* Sets focus on the specified window.
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 8bd3899..d6a6bd2 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -60,10 +60,11 @@
#define INDENT3 " "
using android::base::StringPrintf;
-using namespace android::flag_operators;
namespace android {
+using namespace ftl::flag_operators;
+
static const char* DEVICE_INPUT_PATH = "/dev/input";
// v4l2 devices go directly into /dev
static const char* DEVICE_PATH = "/dev";
@@ -302,7 +303,8 @@
// --- Global Functions ---
-Flags<InputDeviceClass> getAbsAxisUsage(int32_t axis, Flags<InputDeviceClass> deviceClasses) {
+ftl::Flags<InputDeviceClass> getAbsAxisUsage(int32_t axis,
+ ftl::Flags<InputDeviceClass> deviceClasses) {
// Touch devices get dibs on touch-related axes.
if (deviceClasses.test(InputDeviceClass::TOUCH)) {
switch (axis) {
@@ -765,10 +767,10 @@
return device != nullptr ? device->identifier : InputDeviceIdentifier();
}
-Flags<InputDeviceClass> EventHub::getDeviceClasses(int32_t deviceId) const {
+ftl::Flags<InputDeviceClass> EventHub::getDeviceClasses(int32_t deviceId) const {
std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
- return device != nullptr ? device->classes : Flags<InputDeviceClass>(0);
+ return device != nullptr ? device->classes : ftl::Flags<InputDeviceClass>(0);
}
int32_t EventHub::getDeviceControllerNumber(int32_t deviceId) const {
@@ -1909,7 +1911,7 @@
}
void EventHub::reportDeviceAddedForStatisticsLocked(const InputDeviceIdentifier& identifier,
- Flags<InputDeviceClass> classes) {
+ ftl::Flags<InputDeviceClass> classes) {
SHA256_CTX ctx;
SHA256_Init(&ctx);
SHA256_Update(&ctx, reinterpret_cast<const uint8_t*>(identifier.uniqueId.c_str()),
@@ -2191,7 +2193,7 @@
}
// If the device isn't recognized as something we handle, don't monitor it.
- if (device->classes == Flags<InputDeviceClass>(0)) {
+ if (device->classes == ftl::Flags<InputDeviceClass>(0)) {
ALOGV("Dropping device: id=%d, path='%s', name='%s'", deviceId, devicePath.c_str(),
device->identifier.name.c_str());
return;
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index a050963..ba5083b 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -18,9 +18,10 @@
#include "InputDevice.h"
-#include <ftl/Flags.h>
#include <algorithm>
+#include <ftl/flags.h>
+
#include "CursorInputMapper.h"
#include "ExternalStylusInputMapper.h"
#include "InputReaderContext.h"
@@ -145,7 +146,7 @@
return;
}
std::unique_ptr<InputDeviceContext> contextPtr(new InputDeviceContext(*this, eventHubId));
- Flags<InputDeviceClass> classes = contextPtr->getDeviceClasses();
+ ftl::Flags<InputDeviceClass> classes = contextPtr->getDeviceClasses();
std::vector<std::unique_ptr<InputMapper>> mappers;
// Check if we should skip population
@@ -236,7 +237,7 @@
void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config,
uint32_t changes) {
mSources = 0;
- mClasses = Flags<InputDeviceClass>(0);
+ mClasses = ftl::Flags<InputDeviceClass>(0);
mControllerNumber = 0;
for_each_subdevice([this](InputDeviceContext& context) {
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 18e912d..130c556 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -19,13 +19,12 @@
#include <bitset>
#include <climits>
+#include <filesystem>
#include <unordered_map>
#include <vector>
-#include <ftl/Flags.h>
-#include <filesystem>
-
#include <batteryservice/BatteryService.h>
+#include <ftl/flags.h>
#include <input/Input.h>
#include <input/InputDevice.h>
#include <input/KeyCharacterMap.h>
@@ -189,7 +188,7 @@
int32_t id;
std::string name;
std::optional<int32_t> maxBrightness;
- Flags<InputLightClass> flags;
+ ftl::Flags<InputLightClass> flags;
std::array<int32_t, COLOR_NUM> rgbIndex;
std::filesystem::path path;
};
@@ -198,7 +197,7 @@
struct RawBatteryInfo {
int32_t id;
std::string name;
- Flags<InputBatteryClass> flags;
+ ftl::Flags<InputBatteryClass> flags;
std::filesystem::path path;
};
@@ -206,7 +205,8 @@
* Gets the class that owns an axis, in cases where multiple classes might claim
* the same axis for different purposes.
*/
-extern Flags<InputDeviceClass> getAbsAxisUsage(int32_t axis, Flags<InputDeviceClass> deviceClasses);
+extern ftl::Flags<InputDeviceClass> getAbsAxisUsage(int32_t axis,
+ ftl::Flags<InputDeviceClass> deviceClasses);
/*
* Grand Central Station for events.
@@ -239,7 +239,7 @@
FIRST_SYNTHETIC_EVENT = DEVICE_ADDED,
};
- virtual Flags<InputDeviceClass> getDeviceClasses(int32_t deviceId) const = 0;
+ virtual ftl::Flags<InputDeviceClass> getDeviceClasses(int32_t deviceId) const = 0;
virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const = 0;
@@ -436,7 +436,7 @@
public:
EventHub();
- Flags<InputDeviceClass> getDeviceClasses(int32_t deviceId) const override final;
+ ftl::Flags<InputDeviceClass> getDeviceClasses(int32_t deviceId) const override final;
InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const override final;
@@ -559,7 +559,7 @@
std::unique_ptr<TouchVideoDevice> videoDevice;
- Flags<InputDeviceClass> classes;
+ ftl::Flags<InputDeviceClass> classes;
BitArray<KEY_MAX> keyBitmask;
BitArray<KEY_MAX> keyState;
@@ -662,7 +662,7 @@
int32_t getNextControllerNumberLocked(const std::string& name) REQUIRES(mLock);
void releaseControllerNumberLocked(int32_t num) REQUIRES(mLock);
void reportDeviceAddedForStatisticsLocked(const InputDeviceIdentifier& identifier,
- Flags<InputDeviceClass> classes) REQUIRES(mLock);
+ ftl::Flags<InputDeviceClass> classes) REQUIRES(mLock);
const std::unordered_map<int32_t, RawBatteryInfo>& getBatteryInfoLocked(int32_t deviceId) const
REQUIRES(mLock);
@@ -725,6 +725,6 @@
bool mPendingINotify;
};
-}; // namespace android
+} // namespace android
#endif // _RUNTIME_EVENT_HUB_H
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index 694daa9..728020e 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -17,12 +17,12 @@
#ifndef _UI_INPUTREADER_INPUT_DEVICE_H
#define _UI_INPUTREADER_INPUT_DEVICE_H
-#include <ftl/Flags.h>
+#include <ftl/flags.h>
#include <input/DisplayViewport.h>
#include <input/InputDevice.h>
#include <input/PropertyMap.h>
-#include <stdint.h>
+#include <cstdint>
#include <optional>
#include <unordered_map>
#include <vector>
@@ -53,7 +53,7 @@
inline int32_t getGeneration() const { return mGeneration; }
inline const std::string getName() const { return mIdentifier.name; }
inline const std::string getDescriptor() { return mIdentifier.descriptor; }
- inline Flags<InputDeviceClass> getClasses() const { return mClasses; }
+ inline ftl::Flags<InputDeviceClass> getClasses() const { return mClasses; }
inline uint32_t getSources() const { return mSources; }
inline bool hasEventHubDevices() const { return !mDevices.empty(); }
@@ -160,7 +160,7 @@
int32_t mControllerNumber;
InputDeviceIdentifier mIdentifier;
std::string mAlias;
- Flags<InputDeviceClass> mClasses;
+ ftl::Flags<InputDeviceClass> mClasses;
// map from eventHubId to device context and mappers
using MapperVector = std::vector<std::unique_ptr<InputMapper>>;
@@ -250,7 +250,7 @@
inline int32_t getId() { return mDeviceId; }
inline int32_t getEventHubId() { return mId; }
- inline Flags<InputDeviceClass> getDeviceClasses() const {
+ inline ftl::Flags<InputDeviceClass> getDeviceClasses() const {
return mEventHub->getDeviceClasses(mId);
}
inline InputDeviceIdentifier getDeviceIdentifier() const {
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
index 1d63c0e..2ac8178 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -428,6 +428,8 @@
}
void KeyboardInputMapper::updateLedState(bool reset) {
+ // Clear the local led state then union the global led state.
+ mMetaState &= ~(AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON | AMETA_SCROLL_LOCK_ON);
mMetaState |= getContext()->getLedMetaState();
constexpr int32_t META_NUM = 3;
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 9d200bd..76a7c19 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -47,6 +47,7 @@
"InputReader_test.cpp",
"InputFlingerService_test.cpp",
"LatencyTracker_test.cpp",
+ "PreferStylusOverTouch_test.cpp",
"TestInputListener.cpp",
"UinputDevice.cpp",
"UnwantedInteractionBlocker_test.cpp",
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index bf58705..a167271 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -39,10 +39,11 @@
using android::gui::WindowInfoHandle;
using android::os::InputEventInjectionResult;
using android::os::InputEventInjectionSync;
-using namespace android::flag_operators;
namespace android::inputdispatcher {
+using namespace ftl::flag_operators;
+
// An arbitrary time value.
static const nsecs_t ARBITRARY_TIME = 1234;
@@ -55,6 +56,8 @@
static constexpr int32_t POINTER_1_DOWN =
AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+static constexpr int32_t POINTER_2_DOWN =
+ AMOTION_EVENT_ACTION_POINTER_DOWN | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
static constexpr int32_t POINTER_1_UP =
AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
@@ -2244,6 +2247,53 @@
}
/**
+ * This test documents the behavior of WATCH_OUTSIDE_TOUCH. The window will get ACTION_OUTSIDE when
+ * a another pointer causes ACTION_DOWN to be sent to another window for the first time. Only one
+ * ACTION_OUTSIDE event is sent per gesture.
+ */
+TEST_F(InputDispatcherTest, ActionOutsideSentOnlyWhenAWindowIsTouched) {
+ // There are three windows that do not overlap. `window` wants to WATCH_OUTSIDE_TOUCH.
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
+ window->setWatchOutsideTouch(true);
+ window->setFrame(Rect{0, 0, 100, 100});
+ sp<FakeWindowHandle> secondWindow =
+ new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
+ secondWindow->setFrame(Rect{100, 100, 200, 200});
+ sp<FakeWindowHandle> thirdWindow =
+ new FakeWindowHandle(application, mDispatcher, "Third Window", ADISPLAY_ID_DEFAULT);
+ thirdWindow->setFrame(Rect{200, 200, 300, 300});
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, secondWindow, thirdWindow}}});
+
+ // First pointer lands outside all windows. `window` does not get ACTION_OUTSIDE.
+ NotifyMotionArgs motionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {PointF{-10, -10}});
+ mDispatcher->notifyMotion(&motionArgs);
+ window->assertNoEvents();
+ secondWindow->assertNoEvents();
+
+ // The second pointer lands inside `secondWindow`, which should receive a DOWN event.
+ // Now, `window` should get ACTION_OUTSIDE.
+ motionArgs = generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {PointF{-10, -10}, PointF{105, 105}});
+ mDispatcher->notifyMotion(&motionArgs);
+ window->consumeMotionOutside();
+ secondWindow->consumeMotionDown();
+ thirdWindow->assertNoEvents();
+
+ // The third pointer lands inside `thirdWindow`, which should receive a DOWN event. There is
+ // no ACTION_OUTSIDE sent to `window` because one has already been sent for this gesture.
+ motionArgs = generateMotionArgs(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {PointF{-10, -10}, PointF{105, 105}, PointF{205, 205}});
+ mDispatcher->notifyMotion(&motionArgs);
+ window->assertNoEvents();
+ secondWindow->consumeMotionMove();
+ thirdWindow->consumeMotionDown();
+}
+
+/**
* Ensure the correct coordinate spaces are used by InputDispatcher.
*
* InputDispatcher works in the display space, so its coordinate system is relative to the display
@@ -2426,6 +2476,63 @@
secondWindow->consumeMotionUp();
}
+/**
+ * When 'transferTouch' API is invoked, dispatcher needs to find the "best" window to take touch
+ * from. When we have spy windows, there are several windows to choose from: either spy, or the
+ * 'real' (non-spy) window. Always prefer the 'real' window because that's what would be most
+ * natural to the user.
+ * In this test, we are sending a pointer to both spy window and first window. We then try to
+ * transfer touch to the second window. The dispatcher should identify the first window as the
+ * one that should lose the gesture, and therefore the action should be to move the gesture from
+ * the first window to the second.
+ * The main goal here is to test the behaviour of 'transferTouch' API, but it's still valid to test
+ * the other API, as well.
+ */
+TEST_P(TransferTouchFixture, TransferTouch_MultipleWindowsWithSpy) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+
+ // Create a couple of windows + a spy window
+ sp<FakeWindowHandle> spyWindow =
+ new FakeWindowHandle(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
+ spyWindow->setTrustedOverlay(true);
+ spyWindow->setSpy(true);
+ sp<FakeWindowHandle> firstWindow =
+ new FakeWindowHandle(application, mDispatcher, "First", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> secondWindow =
+ new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
+
+ // Add the windows to the dispatcher
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyWindow, firstWindow, secondWindow}}});
+
+ // Send down to the first window
+ NotifyMotionArgs downMotionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyMotion(&downMotionArgs);
+ // Only the first window and spy should get the down event
+ spyWindow->consumeMotionDown();
+ firstWindow->consumeMotionDown();
+
+ // Transfer touch to the second window. Non-spy window should be preferred over the spy window
+ // if f === 'transferTouch'.
+ TransferFunction f = GetParam();
+ const bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
+ ASSERT_TRUE(success);
+ // The first window gets cancel and the second gets down
+ firstWindow->consumeMotionCancel();
+ secondWindow->consumeMotionDown();
+
+ // Send up event to the second window
+ NotifyMotionArgs upMotionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyMotion(&upMotionArgs);
+ // The first window gets no events and the second+spy get up
+ firstWindow->assertNoEvents();
+ spyWindow->consumeMotionUp();
+ secondWindow->consumeMotionUp();
+}
+
TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
@@ -2495,7 +2602,8 @@
::testing::Values(
[&](const std::unique_ptr<InputDispatcher>& dispatcher,
sp<IBinder> /*ignored*/, sp<IBinder> destChannelToken) {
- return dispatcher->transferTouch(destChannelToken);
+ return dispatcher->transferTouch(destChannelToken,
+ ADISPLAY_ID_DEFAULT);
},
[&](const std::unique_ptr<InputDispatcher>& dispatcher,
sp<IBinder> from, sp<IBinder> to) {
@@ -2603,7 +2711,8 @@
secondWindow->consumeMotionDown();
// Transfer touch focus to the second window
- const bool transferred = mDispatcher->transferTouch(secondWindow->getToken());
+ const bool transferred =
+ mDispatcher->transferTouch(secondWindow->getToken(), ADISPLAY_ID_DEFAULT);
// The 'transferTouch' call should not succeed, because there are 2 touched windows
ASSERT_FALSE(transferred);
firstWindow->assertNoEvents();
@@ -2727,7 +2836,7 @@
firstWindowInPrimary->consumeMotionDown(SECOND_DISPLAY_ID);
// Transfer touch focus
- ASSERT_TRUE(mDispatcher->transferTouch(secondWindowInSecondary->getToken()));
+ ASSERT_TRUE(mDispatcher->transferTouch(secondWindowInSecondary->getToken(), SECOND_DISPLAY_ID));
// The first window gets cancel.
firstWindowInPrimary->consumeMotionCancel(SECOND_DISPLAY_ID);
@@ -6335,8 +6444,11 @@
mWindow->consumeFocusEvent(true);
// Set initial touch mode to InputDispatcher::kDefaultInTouchMode.
- mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, INJECTOR_PID,
- INJECTOR_UID, /* hasPermission */ true);
+ if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, INJECTOR_PID,
+ INJECTOR_UID, /* hasPermission */ true)) {
+ mWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
+ mSecondWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
+ }
}
void changeAndVerifyTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission) {
@@ -6381,6 +6493,23 @@
mSecondWindow->assertNoEvents();
}
+TEST_F(InputDispatcherTouchModeChangedTests, CanChangeTouchModeWhenOwningLastInteractedWindow) {
+ // Interact with the window first.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT))
+ << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
+ mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
+
+ // Then remove focus.
+ mWindow->setFocusable(false);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}});
+
+ // Assert that caller can switch touch mode by owning one of the last interacted window.
+ const WindowInfo& windowInfo = *mWindow->getInfo();
+ ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode,
+ windowInfo.ownerPid, windowInfo.ownerUid,
+ /* hasPermission= */ false));
+}
+
class InputDispatcherSpyWindowTest : public InputDispatcherTest {
public:
sp<FakeWindowHandle> createSpy() {
@@ -6665,9 +6794,7 @@
// Third finger goes down outside all windows, so injection should fail.
const MotionEvent thirdFingerDownEvent =
- MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN |
- (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- AINPUT_SOURCE_TOUCHSCREEN)
+ MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
.displayId(ADISPLAY_ID_DEFAULT)
.eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
.pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 9f33d23..bda7755 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+#include <cinttypes>
+#include <memory>
+
#include <CursorInputMapper.h>
#include <InputDevice.h>
#include <InputMapper.h>
@@ -34,18 +37,15 @@
#include <android-base/thread_annotations.h>
#include <gtest/gtest.h>
#include <gui/constants.h>
-#include <inttypes.h>
-#include <math.h>
-#include <memory>
-#include <regex>
#include "input/DisplayViewport.h"
#include "input/Input.h"
namespace android {
+using namespace ftl::flag_operators;
+
using std::chrono_literals::operator""ms;
-using namespace android::flag_operators;
// Timeout for waiting for an expected event
static constexpr std::chrono::duration WAIT_TIMEOUT = 100ms;
@@ -429,7 +429,7 @@
struct Device {
InputDeviceIdentifier identifier;
- Flags<InputDeviceClass> classes;
+ ftl::Flags<InputDeviceClass> classes;
PropertyMap configuration;
KeyedVector<int, RawAbsoluteAxisInfo> absoluteAxes;
KeyedVector<int, bool> relativeAxes;
@@ -457,7 +457,7 @@
return OK;
}
- explicit Device(Flags<InputDeviceClass> classes) : classes(classes), enabled(true) {}
+ explicit Device(ftl::Flags<InputDeviceClass> classes) : classes(classes), enabled(true) {}
};
std::mutex mLock;
@@ -484,7 +484,8 @@
FakeEventHub() { }
- void addDevice(int32_t deviceId, const std::string& name, Flags<InputDeviceClass> classes) {
+ void addDevice(int32_t deviceId, const std::string& name,
+ ftl::Flags<InputDeviceClass> classes) {
Device* device = new Device(classes);
device->identifier.name = name;
mDevices.add(deviceId, device);
@@ -695,9 +696,9 @@
return index >= 0 ? mDevices.valueAt(index) : nullptr;
}
- Flags<InputDeviceClass> getDeviceClasses(int32_t deviceId) const override {
+ ftl::Flags<InputDeviceClass> getDeviceClasses(int32_t deviceId) const override {
Device* device = getDevice(deviceId);
- return device ? device->classes : Flags<InputDeviceClass>(0);
+ return device ? device->classes : ftl::Flags<InputDeviceClass>(0);
}
InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const override {
@@ -1572,8 +1573,8 @@
mFakePolicy.clear();
}
- void addDevice(int32_t eventHubId, const std::string& name, Flags<InputDeviceClass> classes,
- const PropertyMap* configuration) {
+ void addDevice(int32_t eventHubId, const std::string& name,
+ ftl::Flags<InputDeviceClass> classes, const PropertyMap* configuration) {
mFakeEventHub->addDevice(eventHubId, name, classes);
if (configuration) {
@@ -1598,7 +1599,8 @@
FakeInputMapper& addDeviceWithFakeInputMapper(int32_t deviceId, int32_t eventHubId,
const std::string& name,
- Flags<InputDeviceClass> classes, uint32_t sources,
+ ftl::Flags<InputDeviceClass> classes,
+ uint32_t sources,
const PropertyMap* configuration) {
std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, name);
FakeInputMapper& mapper = device->addMapper<FakeInputMapper>(eventHubId, sources);
@@ -1610,7 +1612,7 @@
TEST_F(InputReaderTest, PolicyGetInputDevices) {
ASSERT_NO_FATAL_FAILURE(addDevice(1, "keyboard", InputDeviceClass::KEYBOARD, nullptr));
- ASSERT_NO_FATAL_FAILURE(addDevice(2, "ignored", Flags<InputDeviceClass>(0),
+ ASSERT_NO_FATAL_FAILURE(addDevice(2, "ignored", ftl::Flags<InputDeviceClass>(0),
nullptr)); // no classes so device will be ignored
// Should also have received a notification describing the new input devices.
@@ -1672,7 +1674,7 @@
TEST_F(InputReaderTest, WhenEnabledChanges_SendsDeviceResetNotification) {
constexpr int32_t deviceId = END_RESERVED_ID + 1000;
- constexpr Flags<InputDeviceClass> deviceClass(InputDeviceClass::KEYBOARD);
+ constexpr ftl::Flags<InputDeviceClass> deviceClass(InputDeviceClass::KEYBOARD);
constexpr int32_t eventHubId = 1;
std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake");
// Must add at least one mapper or the device will be ignored!
@@ -1709,7 +1711,7 @@
TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToMappers) {
constexpr int32_t deviceId = END_RESERVED_ID + 1000;
- constexpr Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
+ constexpr ftl::Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
constexpr int32_t eventHubId = 1;
FakeInputMapper& mapper =
addDeviceWithFakeInputMapper(deviceId, eventHubId, "fake", deviceClass,
@@ -1773,7 +1775,7 @@
TEST_F(InputReaderTest, GetScanCodeState_ForwardsRequestsToMappers) {
constexpr int32_t deviceId = END_RESERVED_ID + 1000;
- constexpr Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
+ constexpr ftl::Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
constexpr int32_t eventHubId = 1;
FakeInputMapper& mapper =
addDeviceWithFakeInputMapper(deviceId, eventHubId, "fake", deviceClass,
@@ -1806,7 +1808,7 @@
TEST_F(InputReaderTest, GetSwitchState_ForwardsRequestsToMappers) {
constexpr int32_t deviceId = END_RESERVED_ID + 1000;
- constexpr Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
+ constexpr ftl::Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
constexpr int32_t eventHubId = 1;
FakeInputMapper& mapper =
addDeviceWithFakeInputMapper(deviceId, eventHubId, "fake", deviceClass,
@@ -1839,7 +1841,7 @@
TEST_F(InputReaderTest, MarkSupportedKeyCodes_ForwardsRequestsToMappers) {
constexpr int32_t deviceId = END_RESERVED_ID + 1000;
- constexpr Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
+ constexpr ftl::Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
constexpr int32_t eventHubId = 1;
FakeInputMapper& mapper =
addDeviceWithFakeInputMapper(deviceId, eventHubId, "fake", deviceClass,
@@ -1891,7 +1893,7 @@
TEST_F(InputReaderTest, LoopOnce_ForwardsRawEventsToMappers) {
constexpr int32_t deviceId = END_RESERVED_ID + 1000;
- constexpr Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
+ constexpr ftl::Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
constexpr nsecs_t when = 0;
constexpr int32_t eventHubId = 1;
constexpr nsecs_t readTime = 2;
@@ -1915,7 +1917,7 @@
TEST_F(InputReaderTest, DeviceReset_RandomId) {
constexpr int32_t deviceId = END_RESERVED_ID + 1000;
- constexpr Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
+ constexpr ftl::Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
constexpr int32_t eventHubId = 1;
std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake");
// Must add at least one mapper or the device will be ignored!
@@ -1948,7 +1950,7 @@
TEST_F(InputReaderTest, DeviceReset_GenerateIdWithInputReaderSource) {
constexpr int32_t deviceId = 1;
- constexpr Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
+ constexpr ftl::Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
constexpr int32_t eventHubId = 1;
std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake");
// Must add at least one mapper or the device will be ignored!
@@ -1963,7 +1965,7 @@
TEST_F(InputReaderTest, Device_CanDispatchToDisplay) {
constexpr int32_t deviceId = END_RESERVED_ID + 1000;
- constexpr Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
+ constexpr ftl::Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
constexpr int32_t eventHubId = 1;
const char* DEVICE_LOCATION = "USB1";
std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION);
@@ -2008,7 +2010,7 @@
TEST_F(InputReaderTest, WhenEnabledChanges_AllSubdevicesAreUpdated) {
constexpr int32_t deviceId = END_RESERVED_ID + 1000;
- constexpr Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
+ constexpr ftl::Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
constexpr int32_t eventHubIds[2] = {END_RESERVED_ID, END_RESERVED_ID + 1};
std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake");
// Must add at least one mapper or the device will be ignored!
@@ -2049,7 +2051,7 @@
TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToSubdeviceMappers) {
constexpr int32_t deviceId = END_RESERVED_ID + 1000;
- constexpr Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
+ constexpr ftl::Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
constexpr int32_t eventHubIds[2] = {END_RESERVED_ID, END_RESERVED_ID + 1};
// Add two subdevices to device
std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake");
@@ -2106,7 +2108,8 @@
TEST_F(InputReaderTest, VibratorGetVibratorIds) {
constexpr int32_t deviceId = END_RESERVED_ID + 1000;
- Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::VIBRATOR;
+ ftl::Flags<InputDeviceClass> deviceClass =
+ InputDeviceClass::KEYBOARD | InputDeviceClass::VIBRATOR;
constexpr int32_t eventHubId = 1;
const char* DEVICE_LOCATION = "BLUETOOTH";
std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION);
@@ -2166,7 +2169,8 @@
TEST_F(InputReaderTest, BatteryGetCapacity) {
constexpr int32_t deviceId = END_RESERVED_ID + 1000;
- Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::BATTERY;
+ ftl::Flags<InputDeviceClass> deviceClass =
+ InputDeviceClass::KEYBOARD | InputDeviceClass::BATTERY;
constexpr int32_t eventHubId = 1;
const char* DEVICE_LOCATION = "BLUETOOTH";
std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION);
@@ -2182,7 +2186,8 @@
TEST_F(InputReaderTest, BatteryGetStatus) {
constexpr int32_t deviceId = END_RESERVED_ID + 1000;
- Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::BATTERY;
+ ftl::Flags<InputDeviceClass> deviceClass =
+ InputDeviceClass::KEYBOARD | InputDeviceClass::BATTERY;
constexpr int32_t eventHubId = 1;
const char* DEVICE_LOCATION = "BLUETOOTH";
std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION);
@@ -2198,7 +2203,7 @@
TEST_F(InputReaderTest, LightGetColor) {
constexpr int32_t deviceId = END_RESERVED_ID + 1000;
- Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::LIGHT;
+ ftl::Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::LIGHT;
constexpr int32_t eventHubId = 1;
const char* DEVICE_LOCATION = "BLUETOOTH";
std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION);
@@ -2625,7 +2630,7 @@
static const int32_t DEVICE_ID;
static const int32_t DEVICE_GENERATION;
static const int32_t DEVICE_CONTROLLER_NUMBER;
- static const Flags<InputDeviceClass> DEVICE_CLASSES;
+ static const ftl::Flags<InputDeviceClass> DEVICE_CLASSES;
static const int32_t EVENTHUB_ID;
std::shared_ptr<FakeEventHub> mFakeEventHub;
@@ -2646,7 +2651,7 @@
mDevice = std::make_shared<InputDevice>(mReader->getContext(), DEVICE_ID, DEVICE_GENERATION,
identifier);
mReader->pushNextDevice(mDevice);
- mFakeEventHub->addDevice(EVENTHUB_ID, DEVICE_NAME, Flags<InputDeviceClass>(0));
+ mFakeEventHub->addDevice(EVENTHUB_ID, DEVICE_NAME, ftl::Flags<InputDeviceClass>(0));
mReader->loopOnce();
}
@@ -2661,14 +2666,14 @@
const int32_t InputDeviceTest::DEVICE_ID = END_RESERVED_ID + 1000;
const int32_t InputDeviceTest::DEVICE_GENERATION = 2;
const int32_t InputDeviceTest::DEVICE_CONTROLLER_NUMBER = 0;
-const Flags<InputDeviceClass> InputDeviceTest::DEVICE_CLASSES =
+const ftl::Flags<InputDeviceClass> InputDeviceTest::DEVICE_CLASSES =
InputDeviceClass::KEYBOARD | InputDeviceClass::TOUCH | InputDeviceClass::JOYSTICK;
const int32_t InputDeviceTest::EVENTHUB_ID = 1;
TEST_F(InputDeviceTest, ImmutableProperties) {
ASSERT_EQ(DEVICE_ID, mDevice->getId());
ASSERT_STREQ(DEVICE_NAME, mDevice->getName().c_str());
- ASSERT_EQ(Flags<InputDeviceClass>(0), mDevice->getClasses());
+ ASSERT_EQ(ftl::Flags<InputDeviceClass>(0), mDevice->getClasses());
}
TEST_F(InputDeviceTest, WhenDeviceCreated_EnabledIsFalse) {
@@ -2912,7 +2917,7 @@
static const int32_t DEVICE_ID;
static const int32_t DEVICE_GENERATION;
static const int32_t DEVICE_CONTROLLER_NUMBER;
- static const Flags<InputDeviceClass> DEVICE_CLASSES;
+ static const ftl::Flags<InputDeviceClass> DEVICE_CLASSES;
static const int32_t EVENTHUB_ID;
std::shared_ptr<FakeEventHub> mFakeEventHub;
@@ -2921,7 +2926,7 @@
std::unique_ptr<InstrumentedInputReader> mReader;
std::shared_ptr<InputDevice> mDevice;
- virtual void SetUp(Flags<InputDeviceClass> classes) {
+ virtual void SetUp(ftl::Flags<InputDeviceClass> classes) {
mFakeEventHub = std::make_unique<FakeEventHub>();
mFakePolicy = new FakeInputReaderPolicy();
mFakeListener = std::make_unique<TestInputListener>();
@@ -2953,7 +2958,7 @@
std::shared_ptr<InputDevice> newDevice(int32_t deviceId, const std::string& name,
const std::string& location, int32_t eventHubId,
- Flags<InputDeviceClass> classes) {
+ ftl::Flags<InputDeviceClass> classes) {
InputDeviceIdentifier identifier;
identifier.name = name;
identifier.location = location;
@@ -3045,8 +3050,8 @@
const int32_t InputMapperTest::DEVICE_ID = END_RESERVED_ID + 1000;
const int32_t InputMapperTest::DEVICE_GENERATION = 2;
const int32_t InputMapperTest::DEVICE_CONTROLLER_NUMBER = 0;
-const Flags<InputDeviceClass> InputMapperTest::DEVICE_CLASSES =
- Flags<InputDeviceClass>(0); // not needed for current tests
+const ftl::Flags<InputDeviceClass> InputMapperTest::DEVICE_CLASSES =
+ ftl::Flags<InputDeviceClass>(0); // not needed for current tests
const int32_t InputMapperTest::EVENTHUB_ID = 1;
// --- SwitchInputMapperTest ---
@@ -3842,7 +3847,7 @@
constexpr int32_t SECOND_EVENTHUB_ID = EVENTHUB_ID + 1;
std::shared_ptr<InputDevice> device2 =
newDevice(SECOND_DEVICE_ID, DEVICE_NAME2, USB2, SECOND_EVENTHUB_ID,
- Flags<InputDeviceClass>(0));
+ ftl::Flags<InputDeviceClass>(0));
mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0);
@@ -3954,7 +3959,7 @@
constexpr int32_t SECOND_EVENTHUB_ID = EVENTHUB_ID + 1;
std::shared_ptr<InputDevice> device2 =
newDevice(SECOND_DEVICE_ID, DEVICE_NAME2, USB2, SECOND_EVENTHUB_ID,
- Flags<InputDeviceClass>(0));
+ ftl::Flags<InputDeviceClass>(0));
mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_CAPSL, true /*initially on*/);
mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_NUML, false /*initially off*/);
mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_SCROLLL, false /*initially off*/);
@@ -3994,6 +3999,78 @@
ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper.getMetaState());
}
+TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleInMultiDevices) {
+ // keyboard 1.
+ mFakeEventHub->addLed(EVENTHUB_ID, LED_CAPSL, true /*initially on*/);
+ mFakeEventHub->addLed(EVENTHUB_ID, LED_NUML, false /*initially off*/);
+ mFakeEventHub->addLed(EVENTHUB_ID, LED_SCROLLL, false /*initially off*/);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_CAPSLOCK, 0, AKEYCODE_CAPS_LOCK, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_NUMLOCK, 0, AKEYCODE_NUM_LOCK, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0);
+
+ KeyboardInputMapper& mapper1 =
+ addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
+ AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+
+ // keyboard 2.
+ const std::string USB2 = "USB2";
+ const std::string DEVICE_NAME2 = "KEYBOARD2";
+ constexpr int32_t SECOND_DEVICE_ID = DEVICE_ID + 1;
+ constexpr int32_t SECOND_EVENTHUB_ID = EVENTHUB_ID + 1;
+ std::shared_ptr<InputDevice> device2 =
+ newDevice(SECOND_DEVICE_ID, DEVICE_NAME2, USB2, SECOND_EVENTHUB_ID,
+ ftl::Flags<InputDeviceClass>(0));
+ mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_CAPSL, true /*initially on*/);
+ mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_NUML, false /*initially off*/);
+ mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_SCROLLL, false /*initially off*/);
+ mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_CAPSLOCK, 0, AKEYCODE_CAPS_LOCK, 0);
+ mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_NUMLOCK, 0, AKEYCODE_NUM_LOCK, 0);
+ mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0);
+
+ KeyboardInputMapper& mapper2 =
+ device2->addMapper<KeyboardInputMapper>(SECOND_EVENTHUB_ID, AINPUT_SOURCE_KEYBOARD,
+ AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+ device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0 /*changes*/);
+ device2->reset(ARBITRARY_TIME);
+
+ // Initial metastate is AMETA_NUM_LOCK_ON, turn it off.
+ ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
+ ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper1.getMetaState());
+ ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper2.getMetaState());
+
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 1);
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 0);
+ ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
+ ASSERT_EQ(AMETA_NONE, mapper1.getMetaState());
+ ASSERT_EQ(AMETA_NONE, mapper2.getMetaState());
+
+ // Toggle caps lock on and off.
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 1);
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 0);
+ ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
+ ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper1.getMetaState());
+ ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper2.getMetaState());
+
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 1);
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 0);
+ ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
+ ASSERT_EQ(AMETA_NONE, mapper1.getMetaState());
+ ASSERT_EQ(AMETA_NONE, mapper2.getMetaState());
+
+ // Toggle scroll lock on and off.
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 1);
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 0);
+ ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
+ ASSERT_EQ(AMETA_SCROLL_LOCK_ON, mapper1.getMetaState());
+ ASSERT_EQ(AMETA_SCROLL_LOCK_ON, mapper2.getMetaState());
+
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 1);
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 0);
+ ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
+ ASSERT_EQ(AMETA_NONE, mapper1.getMetaState());
+ ASSERT_EQ(AMETA_NONE, mapper2.getMetaState());
+}
+
// --- KeyboardInputMapperTest_ExternalDevice ---
class KeyboardInputMapperTest_ExternalDevice : public InputMapperTest {
@@ -8409,7 +8486,7 @@
constexpr int32_t SECOND_EVENTHUB_ID = EVENTHUB_ID + 1;
std::shared_ptr<InputDevice> device2 =
newDevice(SECOND_DEVICE_ID, DEVICE_NAME2, USB2, SECOND_EVENTHUB_ID,
- Flags<InputDeviceClass>(0));
+ ftl::Flags<InputDeviceClass>(0));
mFakeEventHub->addAbsoluteAxis(SECOND_EVENTHUB_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX,
0 /*flat*/, 0 /*fuzz*/);
@@ -9350,7 +9427,7 @@
static const int32_t DEVICE_ID;
static const int32_t DEVICE_GENERATION;
static const int32_t DEVICE_CONTROLLER_NUMBER;
- static const Flags<InputDeviceClass> DEVICE_CLASSES;
+ static const ftl::Flags<InputDeviceClass> DEVICE_CLASSES;
static const int32_t EVENTHUB_ID;
std::shared_ptr<FakeEventHub> mFakeEventHub;
@@ -9359,7 +9436,7 @@
std::unique_ptr<InstrumentedInputReader> mReader;
std::shared_ptr<InputDevice> mDevice;
- virtual void SetUp(Flags<InputDeviceClass> classes) {
+ virtual void SetUp(ftl::Flags<InputDeviceClass> classes) {
mFakeEventHub = std::make_unique<FakeEventHub>();
mFakePolicy = new FakeInputReaderPolicy();
mFakeListener = std::make_unique<TestInputListener>();
@@ -9385,7 +9462,7 @@
std::shared_ptr<InputDevice> newDevice(int32_t deviceId, const std::string& name,
const std::string& location, int32_t eventHubId,
- Flags<InputDeviceClass> classes) {
+ ftl::Flags<InputDeviceClass> classes) {
InputDeviceIdentifier identifier;
identifier.name = name;
identifier.location = location;
@@ -9411,8 +9488,8 @@
const int32_t PeripheralControllerTest::DEVICE_ID = END_RESERVED_ID + 1000;
const int32_t PeripheralControllerTest::DEVICE_GENERATION = 2;
const int32_t PeripheralControllerTest::DEVICE_CONTROLLER_NUMBER = 0;
-const Flags<InputDeviceClass> PeripheralControllerTest::DEVICE_CLASSES =
- Flags<InputDeviceClass>(0); // not needed for current tests
+const ftl::Flags<InputDeviceClass> PeripheralControllerTest::DEVICE_CLASSES =
+ ftl::Flags<InputDeviceClass>(0); // not needed for current tests
const int32_t PeripheralControllerTest::EVENTHUB_ID = 1;
// --- BatteryControllerTest ---
diff --git a/services/inputflinger/tests/PreferStylusOverTouch_test.cpp b/services/inputflinger/tests/PreferStylusOverTouch_test.cpp
new file mode 100644
index 0000000..8e2ab88
--- /dev/null
+++ b/services/inputflinger/tests/PreferStylusOverTouch_test.cpp
@@ -0,0 +1,502 @@
+/*
+ * 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 "../PreferStylusOverTouchBlocker.h"
+
+namespace android {
+
+constexpr int32_t TOUCH_DEVICE_ID = 3;
+constexpr int32_t SECOND_TOUCH_DEVICE_ID = 4;
+constexpr int32_t STYLUS_DEVICE_ID = 5;
+constexpr int32_t SECOND_STYLUS_DEVICE_ID = 6;
+
+constexpr int DOWN = AMOTION_EVENT_ACTION_DOWN;
+constexpr int MOVE = AMOTION_EVENT_ACTION_MOVE;
+constexpr int UP = AMOTION_EVENT_ACTION_UP;
+constexpr int CANCEL = AMOTION_EVENT_ACTION_CANCEL;
+static constexpr int32_t POINTER_1_DOWN =
+ AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+constexpr int32_t TOUCHSCREEN = AINPUT_SOURCE_TOUCHSCREEN;
+constexpr int32_t STYLUS = AINPUT_SOURCE_STYLUS;
+
+struct PointerData {
+ float x;
+ float y;
+};
+
+static NotifyMotionArgs generateMotionArgs(nsecs_t downTime, nsecs_t eventTime, int32_t action,
+ const std::vector<PointerData>& points,
+ uint32_t source) {
+ size_t pointerCount = points.size();
+ if (action == DOWN || action == UP) {
+ EXPECT_EQ(1U, pointerCount) << "Actions DOWN and UP can only contain a single pointer";
+ }
+
+ PointerProperties pointerProperties[pointerCount];
+ PointerCoords pointerCoords[pointerCount];
+
+ const int32_t deviceId = isFromSource(source, TOUCHSCREEN) ? TOUCH_DEVICE_ID : STYLUS_DEVICE_ID;
+ const int32_t toolType = isFromSource(source, TOUCHSCREEN) ? AMOTION_EVENT_TOOL_TYPE_FINGER
+ : AMOTION_EVENT_TOOL_TYPE_STYLUS;
+ for (size_t i = 0; i < pointerCount; i++) {
+ pointerProperties[i].clear();
+ pointerProperties[i].id = i;
+ pointerProperties[i].toolType = toolType;
+
+ pointerCoords[i].clear();
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, points[i].x);
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, points[i].y);
+ }
+
+ // Currently, can't have STYLUS source without it also being a TOUCH source. Update the source
+ // accordingly.
+ if (isFromSource(source, STYLUS)) {
+ source |= TOUCHSCREEN;
+ }
+
+ // Define a valid motion event.
+ NotifyMotionArgs args(/* id */ 0, eventTime, 0 /*readTime*/, deviceId, source, 0 /*displayId*/,
+ POLICY_FLAG_PASS_TO_USER, action, /* actionButton */ 0,
+ /* flags */ 0, AMETA_NONE, /* buttonState */ 0,
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, pointerCount,
+ pointerProperties, pointerCoords, /* xPrecision */ 0, /* yPrecision */ 0,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, downTime, /* videoFrames */ {});
+
+ return args;
+}
+
+class PreferStylusOverTouchTest : public testing::Test {
+protected:
+ void assertNotBlocked(const NotifyMotionArgs& args) { assertResponse(args, {args}); }
+
+ void assertDropped(const NotifyMotionArgs& args) { assertResponse(args, {}); }
+
+ void assertResponse(const NotifyMotionArgs& args,
+ const std::vector<NotifyMotionArgs>& expected) {
+ std::vector<NotifyMotionArgs> receivedArgs = mBlocker.processMotion(args);
+ ASSERT_EQ(expected.size(), receivedArgs.size());
+ for (size_t i = 0; i < expected.size(); i++) {
+ // The 'eventTime' of CANCEL events is dynamically generated. Don't check this field.
+ if (expected[i].action == CANCEL && receivedArgs[i].action == CANCEL) {
+ receivedArgs[i].eventTime = expected[i].eventTime;
+ }
+
+ ASSERT_EQ(expected[i], receivedArgs[i])
+ << expected[i].dump() << " vs " << receivedArgs[i].dump();
+ }
+ }
+
+ void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& devices) {
+ mBlocker.notifyInputDevicesChanged(devices);
+ }
+
+ void dump() const { ALOGI("Blocker: \n%s\n", mBlocker.dump().c_str()); }
+
+private:
+ PreferStylusOverTouchBlocker mBlocker;
+};
+
+TEST_F(PreferStylusOverTouchTest, TouchGestureIsNotBlocked) {
+ NotifyMotionArgs args;
+
+ args = generateMotionArgs(0 /*downTime*/, 0 /*eventTime*/, DOWN, {{1, 2}}, TOUCHSCREEN);
+ assertNotBlocked(args);
+
+ args = generateMotionArgs(0 /*downTime*/, 1 /*eventTime*/, MOVE, {{1, 3}}, TOUCHSCREEN);
+ assertNotBlocked(args);
+
+ args = generateMotionArgs(0 /*downTime*/, 2 /*eventTime*/, UP, {{1, 3}}, TOUCHSCREEN);
+ assertNotBlocked(args);
+}
+
+TEST_F(PreferStylusOverTouchTest, StylusGestureIsNotBlocked) {
+ NotifyMotionArgs args;
+
+ args = generateMotionArgs(0 /*downTime*/, 0 /*eventTime*/, DOWN, {{1, 2}}, STYLUS);
+ assertNotBlocked(args);
+
+ args = generateMotionArgs(0 /*downTime*/, 1 /*eventTime*/, MOVE, {{1, 3}}, STYLUS);
+ assertNotBlocked(args);
+
+ args = generateMotionArgs(0 /*downTime*/, 2 /*eventTime*/, UP, {{1, 3}}, STYLUS);
+ assertNotBlocked(args);
+}
+
+/**
+ * Existing touch gesture should be canceled when stylus goes down. There should be an ACTION_CANCEL
+ * event generated.
+ */
+TEST_F(PreferStylusOverTouchTest, TouchIsCanceledWhenStylusGoesDown) {
+ NotifyMotionArgs args;
+
+ args = generateMotionArgs(0 /*downTime*/, 0 /*eventTime*/, DOWN, {{1, 2}}, TOUCHSCREEN);
+ assertNotBlocked(args);
+
+ args = generateMotionArgs(0 /*downTime*/, 1 /*eventTime*/, MOVE, {{1, 3}}, TOUCHSCREEN);
+ assertNotBlocked(args);
+
+ args = generateMotionArgs(3 /*downTime*/, 3 /*eventTime*/, DOWN, {{10, 30}}, STYLUS);
+ NotifyMotionArgs cancelArgs =
+ generateMotionArgs(0 /*downTime*/, 1 /*eventTime*/, CANCEL, {{1, 3}}, TOUCHSCREEN);
+ cancelArgs.flags |= AMOTION_EVENT_FLAG_CANCELED;
+ assertResponse(args, {cancelArgs, args});
+
+ // Both stylus and touch events continue. Stylus should be not blocked, and touch should be
+ // blocked
+ args = generateMotionArgs(3 /*downTime*/, 4 /*eventTime*/, MOVE, {{10, 31}}, STYLUS);
+ assertNotBlocked(args);
+
+ args = generateMotionArgs(0 /*downTime*/, 5 /*eventTime*/, MOVE, {{1, 4}}, TOUCHSCREEN);
+ assertDropped(args);
+}
+
+/**
+ * Stylus goes down after touch gesture.
+ */
+TEST_F(PreferStylusOverTouchTest, StylusDownAfterTouch) {
+ NotifyMotionArgs args;
+
+ args = generateMotionArgs(0 /*downTime*/, 0 /*eventTime*/, DOWN, {{1, 2}}, TOUCHSCREEN);
+ assertNotBlocked(args);
+
+ args = generateMotionArgs(0 /*downTime*/, 1 /*eventTime*/, MOVE, {{1, 3}}, TOUCHSCREEN);
+ assertNotBlocked(args);
+
+ args = generateMotionArgs(0 /*downTime*/, 2 /*eventTime*/, UP, {{1, 3}}, TOUCHSCREEN);
+ assertNotBlocked(args);
+
+ // Stylus goes down
+ args = generateMotionArgs(3 /*downTime*/, 3 /*eventTime*/, DOWN, {{10, 30}}, STYLUS);
+ assertNotBlocked(args);
+}
+
+/**
+ * New touch events should be simply blocked (dropped) when stylus is down. No CANCEL event should
+ * be generated.
+ */
+TEST_F(PreferStylusOverTouchTest, NewTouchIsBlockedWhenStylusIsDown) {
+ NotifyMotionArgs args;
+ constexpr nsecs_t stylusDownTime = 0;
+ constexpr nsecs_t touchDownTime = 1;
+
+ args = generateMotionArgs(stylusDownTime, 0 /*eventTime*/, DOWN, {{10, 30}}, STYLUS);
+ assertNotBlocked(args);
+
+ args = generateMotionArgs(touchDownTime, 1 /*eventTime*/, DOWN, {{1, 2}}, TOUCHSCREEN);
+ assertDropped(args);
+
+ // Stylus should continue to work
+ args = generateMotionArgs(stylusDownTime, 2 /*eventTime*/, MOVE, {{10, 31}}, STYLUS);
+ assertNotBlocked(args);
+
+ // Touch should continue to be blocked
+ args = generateMotionArgs(touchDownTime, 1 /*eventTime*/, MOVE, {{1, 3}}, TOUCHSCREEN);
+ assertDropped(args);
+
+ args = generateMotionArgs(0 /*downTime*/, 5 /*eventTime*/, MOVE, {{1, 4}}, TOUCHSCREEN);
+ assertDropped(args);
+}
+
+/**
+ * New touch events should be simply blocked (dropped) when stylus is down. No CANCEL event should
+ * be generated.
+ */
+TEST_F(PreferStylusOverTouchTest, NewTouchWorksAfterStylusIsLifted) {
+ NotifyMotionArgs args;
+ constexpr nsecs_t stylusDownTime = 0;
+ constexpr nsecs_t touchDownTime = 4;
+
+ // Stylus goes down and up
+ args = generateMotionArgs(stylusDownTime, 0 /*eventTime*/, DOWN, {{10, 30}}, STYLUS);
+ assertNotBlocked(args);
+
+ args = generateMotionArgs(stylusDownTime, 2 /*eventTime*/, MOVE, {{10, 31}}, STYLUS);
+ assertNotBlocked(args);
+
+ args = generateMotionArgs(stylusDownTime, 3 /*eventTime*/, UP, {{10, 31}}, STYLUS);
+ assertNotBlocked(args);
+
+ // New touch goes down. It should not be blocked
+ args = generateMotionArgs(touchDownTime, touchDownTime, DOWN, {{1, 2}}, TOUCHSCREEN);
+ assertNotBlocked(args);
+
+ args = generateMotionArgs(touchDownTime, 5 /*eventTime*/, MOVE, {{1, 3}}, TOUCHSCREEN);
+ assertNotBlocked(args);
+
+ args = generateMotionArgs(touchDownTime, 6 /*eventTime*/, UP, {{1, 3}}, TOUCHSCREEN);
+ assertNotBlocked(args);
+}
+
+/**
+ * Once a touch gesture is canceled, it should continue to be canceled, even if the stylus has been
+ * lifted.
+ */
+TEST_F(PreferStylusOverTouchTest, AfterStylusIsLiftedCurrentTouchIsBlocked) {
+ NotifyMotionArgs args;
+ constexpr nsecs_t stylusDownTime = 0;
+ constexpr nsecs_t touchDownTime = 1;
+
+ assertNotBlocked(generateMotionArgs(stylusDownTime, 0 /*eventTime*/, DOWN, {{10, 30}}, STYLUS));
+
+ args = generateMotionArgs(touchDownTime, 1 /*eventTime*/, DOWN, {{1, 2}}, TOUCHSCREEN);
+ assertDropped(args);
+
+ // Lift the stylus
+ args = generateMotionArgs(stylusDownTime, 2 /*eventTime*/, UP, {{10, 30}}, STYLUS);
+ assertNotBlocked(args);
+
+ // Touch should continue to be blocked
+ args = generateMotionArgs(touchDownTime, 3 /*eventTime*/, MOVE, {{1, 3}}, TOUCHSCREEN);
+ assertDropped(args);
+
+ args = generateMotionArgs(touchDownTime, 4 /*eventTime*/, UP, {{1, 3}}, TOUCHSCREEN);
+ assertDropped(args);
+
+ // New touch should go through, though.
+ constexpr nsecs_t newTouchDownTime = 5;
+ args = generateMotionArgs(newTouchDownTime, 5 /*eventTime*/, DOWN, {{10, 20}}, TOUCHSCREEN);
+ assertNotBlocked(args);
+}
+
+/**
+ * If an event with mixed stylus and touch pointers is encountered, it should be ignored. Touches
+ * from such should pass, even if stylus from the same device goes down.
+ */
+TEST_F(PreferStylusOverTouchTest, MixedStylusAndTouchPointersAreIgnored) {
+ NotifyMotionArgs args;
+
+ // Event from a stylus device, but with finger tool type
+ args = generateMotionArgs(1 /*downTime*/, 1 /*eventTime*/, DOWN, {{1, 2}}, STYLUS);
+ // Keep source stylus, but make the tool type touch
+ args.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+ assertNotBlocked(args);
+
+ // Second pointer (stylus pointer) goes down, from the same device
+ args = generateMotionArgs(1 /*downTime*/, 2 /*eventTime*/, POINTER_1_DOWN, {{1, 2}, {10, 20}},
+ STYLUS);
+ // Keep source stylus, but make the tool type touch
+ args.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+ assertNotBlocked(args);
+
+ // Second pointer (stylus pointer) goes down, from the same device
+ args = generateMotionArgs(1 /*downTime*/, 3 /*eventTime*/, MOVE, {{2, 3}, {11, 21}}, STYLUS);
+ // Keep source stylus, but make the tool type touch
+ args.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+ assertNotBlocked(args);
+}
+
+/**
+ * When there are two touch devices, stylus down should cancel all current touch streams.
+ */
+TEST_F(PreferStylusOverTouchTest, TouchFromTwoDevicesAndStylus) {
+ NotifyMotionArgs touch1Down =
+ generateMotionArgs(1 /*downTime*/, 1 /*eventTime*/, DOWN, {{1, 2}}, TOUCHSCREEN);
+ assertNotBlocked(touch1Down);
+
+ NotifyMotionArgs touch2Down =
+ generateMotionArgs(2 /*downTime*/, 2 /*eventTime*/, DOWN, {{3, 4}}, TOUCHSCREEN);
+ touch2Down.deviceId = SECOND_TOUCH_DEVICE_ID;
+ assertNotBlocked(touch2Down);
+
+ NotifyMotionArgs stylusDown =
+ generateMotionArgs(3 /*downTime*/, 3 /*eventTime*/, DOWN, {{10, 30}}, STYLUS);
+ NotifyMotionArgs cancelArgs1 = touch1Down;
+ cancelArgs1.action = CANCEL;
+ cancelArgs1.flags |= AMOTION_EVENT_FLAG_CANCELED;
+ NotifyMotionArgs cancelArgs2 = touch2Down;
+ cancelArgs2.action = CANCEL;
+ cancelArgs2.flags |= AMOTION_EVENT_FLAG_CANCELED;
+ assertResponse(stylusDown, {cancelArgs1, cancelArgs2, stylusDown});
+}
+
+/**
+ * Touch should be canceled when stylus goes down. After the stylus lifts up, the touch from that
+ * device should continue to be canceled.
+ * If one of the devices is already canceled, it should remain canceled, but new touches from a
+ * different device should go through.
+ */
+TEST_F(PreferStylusOverTouchTest, AllTouchMustLiftAfterCanceledByStylus) {
+ // First device touches down
+ NotifyMotionArgs touch1Down =
+ generateMotionArgs(1 /*downTime*/, 1 /*eventTime*/, DOWN, {{1, 2}}, TOUCHSCREEN);
+ assertNotBlocked(touch1Down);
+
+ // Stylus goes down - touch should be canceled
+ NotifyMotionArgs stylusDown =
+ generateMotionArgs(2 /*downTime*/, 2 /*eventTime*/, DOWN, {{10, 30}}, STYLUS);
+ NotifyMotionArgs cancelArgs1 = touch1Down;
+ cancelArgs1.action = CANCEL;
+ cancelArgs1.flags |= AMOTION_EVENT_FLAG_CANCELED;
+ assertResponse(stylusDown, {cancelArgs1, stylusDown});
+
+ // Stylus goes up
+ NotifyMotionArgs stylusUp =
+ generateMotionArgs(2 /*downTime*/, 3 /*eventTime*/, UP, {{10, 30}}, STYLUS);
+ assertNotBlocked(stylusUp);
+
+ // Touch from the first device remains blocked
+ NotifyMotionArgs touch1Move =
+ generateMotionArgs(1 /*downTime*/, 4 /*eventTime*/, MOVE, {{2, 3}}, TOUCHSCREEN);
+ assertDropped(touch1Move);
+
+ // Second touch goes down. It should not be blocked because stylus has already lifted.
+ NotifyMotionArgs touch2Down =
+ generateMotionArgs(5 /*downTime*/, 5 /*eventTime*/, DOWN, {{31, 32}}, TOUCHSCREEN);
+ touch2Down.deviceId = SECOND_TOUCH_DEVICE_ID;
+ assertNotBlocked(touch2Down);
+
+ // First device is lifted up. It's already been canceled, so the UP event should be dropped.
+ NotifyMotionArgs touch1Up =
+ generateMotionArgs(1 /*downTime*/, 6 /*eventTime*/, UP, {{2, 3}}, TOUCHSCREEN);
+ assertDropped(touch1Up);
+
+ // Touch from second device touch should continue to work
+ NotifyMotionArgs touch2Move =
+ generateMotionArgs(5 /*downTime*/, 7 /*eventTime*/, MOVE, {{32, 33}}, TOUCHSCREEN);
+ touch2Move.deviceId = SECOND_TOUCH_DEVICE_ID;
+ assertNotBlocked(touch2Move);
+
+ // Second touch lifts up
+ NotifyMotionArgs touch2Up =
+ generateMotionArgs(5 /*downTime*/, 8 /*eventTime*/, UP, {{32, 33}}, TOUCHSCREEN);
+ touch2Up.deviceId = SECOND_TOUCH_DEVICE_ID;
+ assertNotBlocked(touch2Up);
+
+ // Now that all touch has been lifted, new touch from either first or second device should work
+ NotifyMotionArgs touch3Down =
+ generateMotionArgs(9 /*downTime*/, 9 /*eventTime*/, DOWN, {{1, 2}}, TOUCHSCREEN);
+ assertNotBlocked(touch3Down);
+
+ NotifyMotionArgs touch4Down =
+ generateMotionArgs(10 /*downTime*/, 10 /*eventTime*/, DOWN, {{100, 200}}, TOUCHSCREEN);
+ touch4Down.deviceId = SECOND_TOUCH_DEVICE_ID;
+ assertNotBlocked(touch4Down);
+}
+
+/**
+ * When we don't know that a specific device does both stylus and touch, and we only see touch
+ * pointers from it, we should treat it as a touch device. That means, the device events should be
+ * canceled when stylus from another device goes down. When we detect simultaneous touch and stylus
+ * from this device though, we should just pass this device through without canceling anything.
+ *
+ * In this test:
+ * 1. Start by touching down with device 1
+ * 2. Device 2 has stylus going down
+ * 3. Device 1 should be canceled.
+ * 4. When we add stylus pointers to the device 1, they should continue to be canceled.
+ * 5. Device 1 lifts up.
+ * 6. Subsequent events from device 1 should not be canceled even if stylus is down.
+ * 7. If a reset happens, and such device is no longer there, then we should
+ * Therefore, the device 1 is "ignored" and does not participate into "prefer stylus over touch"
+ * behaviour.
+ */
+TEST_F(PreferStylusOverTouchTest, MixedStylusAndTouchDeviceIsCanceledAtFirst) {
+ // Touch from device 1 goes down
+ NotifyMotionArgs touchDown =
+ generateMotionArgs(1 /*downTime*/, 1 /*eventTime*/, DOWN, {{1, 2}}, TOUCHSCREEN);
+ touchDown.source = STYLUS;
+ assertNotBlocked(touchDown);
+
+ // Stylus from device 2 goes down. Touch should be canceled.
+ NotifyMotionArgs args =
+ generateMotionArgs(2 /*downTime*/, 2 /*eventTime*/, DOWN, {{10, 20}}, STYLUS);
+ NotifyMotionArgs cancelTouchArgs = touchDown;
+ cancelTouchArgs.action = CANCEL;
+ cancelTouchArgs.flags |= AMOTION_EVENT_FLAG_CANCELED;
+ assertResponse(args, {cancelTouchArgs, args});
+
+ // Introduce a stylus pointer into the device 1 stream. It should be ignored.
+ args = generateMotionArgs(1 /*downTime*/, 3 /*eventTime*/, POINTER_1_DOWN, {{1, 2}, {3, 4}},
+ TOUCHSCREEN);
+ args.pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+ args.source = STYLUS;
+ assertDropped(args);
+
+ // Lift up touch from the mixed touch/stylus device
+ args = generateMotionArgs(1 /*downTime*/, 4 /*eventTime*/, CANCEL, {{1, 2}, {3, 4}},
+ TOUCHSCREEN);
+ args.pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+ args.source = STYLUS;
+ assertDropped(args);
+
+ // Stylus from device 2 is still down. Since the device 1 is now identified as a mixed
+ // touch/stylus device, its events should go through, even if they are touch.
+ args = generateMotionArgs(5 /*downTime*/, 5 /*eventTime*/, DOWN, {{21, 22}}, TOUCHSCREEN);
+ touchDown.source = STYLUS;
+ assertResponse(args, {args});
+
+ // Reconfigure such that only the stylus device remains
+ InputDeviceInfo stylusDevice;
+ stylusDevice.initialize(STYLUS_DEVICE_ID, 1 /*generation*/, 1 /*controllerNumber*/,
+ {} /*identifier*/, "stylus device", false /*external*/,
+ false /*hasMic*/);
+ notifyInputDevicesChanged({stylusDevice});
+ // The touchscreen device was removed, so we no longer remember anything about it. We should
+ // again start blocking touch events from it.
+ args = generateMotionArgs(6 /*downTime*/, 6 /*eventTime*/, DOWN, {{1, 2}}, TOUCHSCREEN);
+ args.source = STYLUS;
+ assertDropped(args);
+}
+
+/**
+ * If two styli are active at the same time, touch should be blocked until both of them are lifted.
+ * If one of them lifts, touch should continue to be blocked.
+ */
+TEST_F(PreferStylusOverTouchTest, TouchIsBlockedWhenTwoStyliAreUsed) {
+ NotifyMotionArgs args;
+
+ // First stylus is down
+ assertNotBlocked(generateMotionArgs(0 /*downTime*/, 0 /*eventTime*/, DOWN, {{10, 30}}, STYLUS));
+
+ // Second stylus is down
+ args = generateMotionArgs(1 /*downTime*/, 1 /*eventTime*/, DOWN, {{20, 40}}, STYLUS);
+ args.deviceId = SECOND_STYLUS_DEVICE_ID;
+ assertNotBlocked(args);
+
+ // Touch goes down. It should be ignored.
+ args = generateMotionArgs(2 /*downTime*/, 2 /*eventTime*/, DOWN, {{1, 2}}, TOUCHSCREEN);
+ assertDropped(args);
+
+ // Lift the first stylus
+ args = generateMotionArgs(0 /*downTime*/, 3 /*eventTime*/, UP, {{10, 30}}, STYLUS);
+ assertNotBlocked(args);
+
+ // Touch should continue to be blocked
+ args = generateMotionArgs(2 /*downTime*/, 4 /*eventTime*/, UP, {{1, 2}}, TOUCHSCREEN);
+ assertDropped(args);
+
+ // New touch should be blocked because second stylus is still down
+ args = generateMotionArgs(5 /*downTime*/, 5 /*eventTime*/, DOWN, {{5, 6}}, TOUCHSCREEN);
+ assertDropped(args);
+
+ // Second stylus goes up
+ args = generateMotionArgs(1 /*downTime*/, 6 /*eventTime*/, UP, {{20, 40}}, STYLUS);
+ args.deviceId = SECOND_STYLUS_DEVICE_ID;
+ assertNotBlocked(args);
+
+ // Current touch gesture should continue to be blocked
+ // Touch should continue to be blocked
+ args = generateMotionArgs(5 /*downTime*/, 7 /*eventTime*/, UP, {{5, 6}}, TOUCHSCREEN);
+ assertDropped(args);
+
+ // Now that all styli were lifted, new touch should go through
+ args = generateMotionArgs(8 /*downTime*/, 8 /*eventTime*/, DOWN, {{7, 8}}, TOUCHSCREEN);
+ assertNotBlocked(args);
+}
+
+} // namespace android
diff --git a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
index a3220cc..e378096 100644
--- a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
+++ b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
@@ -490,6 +490,14 @@
&(args = generateMotionArgs(0 /*downTime*/, 4 /*eventTime*/, DOWN, {{7, 8, 9}})));
}
+TEST_F(UnwantedInteractionBlockerTest, NoCrashWhenStylusSourceWithFingerToolIsReceived) {
+ mBlocker->notifyInputDevicesChanged({generateTestDeviceInfo()});
+ NotifyMotionArgs args = generateMotionArgs(0 /*downTime*/, 1 /*eventTime*/, DOWN, {{1, 2, 3}});
+ args.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+ args.source = AINPUT_SOURCE_STYLUS;
+ mBlocker->notifyMotion(&args);
+}
+
/**
* If input devices have changed, but the important device info that's used by the
* UnwantedInteractionBlocker has not changed, there should not be a reset.
@@ -511,6 +519,34 @@
&(args = generateMotionArgs(0 /*downTime*/, 4 /*eventTime*/, MOVE, {{7, 8, 9}})));
}
+/**
+ * Send a touch event, and then a stylus event. Make sure that both work.
+ */
+TEST_F(UnwantedInteractionBlockerTest, StylusAfterTouchWorks) {
+ NotifyMotionArgs args;
+ mBlocker->notifyInputDevicesChanged({generateTestDeviceInfo()});
+ args = generateMotionArgs(0 /*downTime*/, 0 /*eventTime*/, DOWN, {{1, 2, 3}});
+ mBlocker->notifyMotion(&args);
+ args = generateMotionArgs(0 /*downTime*/, 1 /*eventTime*/, MOVE, {{4, 5, 6}});
+ mBlocker->notifyMotion(&args);
+ args = generateMotionArgs(0 /*downTime*/, 2 /*eventTime*/, UP, {{4, 5, 6}});
+ mBlocker->notifyMotion(&args);
+
+ // Now touch down stylus
+ args = generateMotionArgs(3 /*downTime*/, 3 /*eventTime*/, DOWN, {{10, 20, 30}});
+ args.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+ args.source |= AINPUT_SOURCE_STYLUS;
+ mBlocker->notifyMotion(&args);
+ args = generateMotionArgs(3 /*downTime*/, 4 /*eventTime*/, MOVE, {{40, 50, 60}});
+ args.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+ args.source |= AINPUT_SOURCE_STYLUS;
+ mBlocker->notifyMotion(&args);
+ args = generateMotionArgs(3 /*downTime*/, 5 /*eventTime*/, UP, {{40, 50, 60}});
+ args.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+ args.source |= AINPUT_SOURCE_STYLUS;
+ mBlocker->notifyMotion(&args);
+}
+
using UnwantedInteractionBlockerTestDeathTest = UnwantedInteractionBlockerTest;
/**
diff --git a/services/sensorservice/HidlSensorHalWrapper.cpp b/services/sensorservice/HidlSensorHalWrapper.cpp
index 4c64e59..c55c9b4 100644
--- a/services/sensorservice/HidlSensorHalWrapper.cpp
+++ b/services/sensorservice/HidlSensorHalWrapper.cpp
@@ -281,7 +281,7 @@
}
status_t HidlSensorHalWrapper::registerDirectChannel(const sensors_direct_mem_t* memory,
- int32_t* /*channelHandle*/) {
+ int32_t* outChannelHandle) {
if (mSensors == nullptr) return NO_INIT;
SharedMemType type;
@@ -309,14 +309,16 @@
.memoryHandle = memory->handle,
};
- status_t ret;
- checkReturn(mSensors->registerDirectChannel(mem, [&ret](auto result, auto channelHandle) {
- if (result == Result::OK) {
- ret = channelHandle;
- } else {
- ret = statusFromResult(result);
- }
- }));
+ status_t ret = OK;
+ checkReturn(mSensors->registerDirectChannel(mem,
+ [&ret, &outChannelHandle](auto result,
+ auto channelHandle) {
+ if (result == Result::OK) {
+ *outChannelHandle = channelHandle;
+ } else {
+ ret = statusFromResult(result);
+ }
+ }));
return ret;
}
diff --git a/services/sensorservice/HidlSensorHalWrapper.h b/services/sensorservice/HidlSensorHalWrapper.h
index 71c3512..d6ed178 100644
--- a/services/sensorservice/HidlSensorHalWrapper.h
+++ b/services/sensorservice/HidlSensorHalWrapper.h
@@ -112,7 +112,7 @@
virtual status_t injectSensorData(const sensors_event_t* event) override;
virtual status_t registerDirectChannel(const sensors_direct_mem_t* memory,
- int32_t* channelHandle) override;
+ int32_t* outChannelHandle) override;
virtual status_t unregisterDirectChannel(int32_t channelHandle) override;
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index a0e30ac..53a3025 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -766,7 +766,13 @@
if (mHalWrapper == nullptr) return NO_INIT;
Mutex::Autolock _l(mLock);
- return mHalWrapper->registerDirectChannel(memory, nullptr);
+ int32_t channelHandle;
+ status_t status = mHalWrapper->registerDirectChannel(memory, &channelHandle);
+ if (status != OK) {
+ channelHandle = -1;
+ }
+
+ return channelHandle;
}
void SensorDevice::unregisterDirectChannel(int32_t channelHandle) {
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 3c164aa..8b81d48 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -2030,7 +2030,9 @@
// Runtime permissions can't use the cache as they may change.
if (sensor.isRequiredPermissionRuntime()) {
hasPermission = checkPermission(String16(requiredPermission),
- IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid());
+ IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid(),
+ /*logPermissionFailure=*/ false);
} else {
hasPermission = PermissionCache::checkCallingPermission(String16(requiredPermission));
}
@@ -2211,7 +2213,8 @@
int targetSdk = getTargetSdkVersion(opPackageName);
bool hasSamplingRatePermission = checkPermission(sAccessHighSensorSamplingRatePermission,
IPCThreadState::self()->getCallingPid(),
- IPCThreadState::self()->getCallingUid());
+ IPCThreadState::self()->getCallingUid(),
+ /*logPermissionFailure=*/ false);
if (targetSdk < __ANDROID_API_S__ ||
(targetSdk >= __ANDROID_API_S__ && hasSamplingRatePermission)) {
return false;
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 7194db3..b18d204 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -257,11 +257,13 @@
bool isUidActive(uid_t uid);
- void onUidGone(uid_t uid, bool disabled);
- void onUidActive(uid_t uid);
- void onUidIdle(uid_t uid, bool disabled);
+ void onUidGone(uid_t uid, bool disabled) override;
+ void onUidActive(uid_t uid) override;
+ void onUidIdle(uid_t uid, bool disabled) override;
void onUidStateChanged(uid_t uid __unused, int32_t procState __unused,
- int64_t procStateSeq __unused, int32_t capability __unused) {}
+ int64_t procStateSeq __unused,
+ int32_t capability __unused) override {}
+ void onUidProcAdjChanged(uid_t uid __unused) override {}
void addOverrideUid(uid_t uid, bool active);
void removeOverrideUid(uid_t uid);
diff --git a/services/sensorservice/SensorServiceUtils.cpp b/services/sensorservice/SensorServiceUtils.cpp
index 7dd2331..6bad962 100644
--- a/services/sensorservice/SensorServiceUtils.cpp
+++ b/services/sensorservice/SensorServiceUtils.cpp
@@ -39,6 +39,7 @@
return 5;
case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
+ case SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED:
case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
case SENSOR_TYPE_ACCELEROMETER_LIMITED_AXES:
case SENSOR_TYPE_GYROSCOPE_LIMITED_AXES:
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index bcae8d9..c5d7a60 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -1098,6 +1098,13 @@
}
}
+ if (s.what & layer_state_t::eDimmingEnabledChanged) {
+ if (mDrawingState.dimmingEnabled != s.dimmingEnabled) {
+ ALOGV("%s: false [eDimmingEnabledChanged changed]", __func__);
+ return false;
+ }
+ }
+
ALOGV("%s: true", __func__);
return true;
}
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index aefc014..11a9e19 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -23,6 +23,7 @@
"android.hardware.graphics.composer3-V1-ndk",
"android.hardware.power@1.0",
"android.hardware.power@1.3",
+ "android.hardware.power-V2-cpp",
"libbase",
"libcutils",
"libgui",
@@ -41,6 +42,10 @@
"libtonemap",
"libtrace_proto",
"libaidlcommonsupport",
+ "libprocessgroup",
+ "libcgrouprc",
+ "libjsoncpp",
+ "libcgrouprc_format",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
@@ -68,6 +73,7 @@
"src/DisplayColorProfile.cpp",
"src/DisplaySurface.cpp",
"src/DumpHelpers.cpp",
+ "src/HwcAsyncWorker.cpp",
"src/HwcBufferCache.cpp",
"src/LayerFECompositionState.cpp",
"src/Output.cpp",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h
index c553fce..ca86f4c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h
@@ -72,6 +72,9 @@
virtual void resizeBuffers(const ui::Size&) = 0;
virtual const sp<Fence>& getClientTargetAcquireFence() const = 0;
+
+ // Returns true if the render surface supports client composition prediction.
+ virtual bool supportsCompositionStrategyPrediction() const;
};
} // namespace compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index 283fe86..974f7c6 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -207,6 +207,9 @@
// framerate of the layer as measured by LayerHistory
float fps;
+ // The dimming flag
+ bool dimmingEnabled{true};
+
virtual ~LayerFECompositionState();
// Debugging
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index d8644a4..5846e67 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -35,6 +35,7 @@
#include <utils/Vector.h>
#include <ui/DisplayIdentification.h>
+#include "DisplayHardware/HWComposer.h"
namespace android {
@@ -54,6 +55,7 @@
namespace impl {
struct OutputCompositionState;
+struct GpuCompositionResult;
} // namespace impl
/**
@@ -262,6 +264,9 @@
// Latches the front-end layer state for each output layer
virtual void updateLayerStateFromFE(const CompositionRefreshArgs&) const = 0;
+ // Enables predicting composition strategy to run client composition earlier
+ virtual void setPredictCompositionStrategy(bool) = 0;
+
protected:
virtual void setDisplayColorProfile(std::unique_ptr<DisplayColorProfile>) = 0;
virtual void setRenderSurface(std::unique_ptr<RenderSurface>) = 0;
@@ -278,13 +283,22 @@
virtual void updateColorProfile(const CompositionRefreshArgs&) = 0;
virtual void beginFrame() = 0;
virtual void prepareFrame() = 0;
+
+ using GpuCompositionResult = compositionengine::impl::GpuCompositionResult;
+ // Runs prepare frame in another thread while running client composition using
+ // the previous frame's composition strategy.
+ virtual GpuCompositionResult prepareFrameAsync(const CompositionRefreshArgs&) = 0;
virtual void devOptRepaintFlash(const CompositionRefreshArgs&) = 0;
- virtual void finishFrame(const CompositionRefreshArgs&) = 0;
+ virtual void finishFrame(const CompositionRefreshArgs&, GpuCompositionResult&&) = 0;
virtual std::optional<base::unique_fd> composeSurfaces(
- const Region&, const compositionengine::CompositionRefreshArgs& refreshArgs) = 0;
+ const Region&, const compositionengine::CompositionRefreshArgs&,
+ std::shared_ptr<renderengine::ExternalTexture>, base::unique_fd&) = 0;
virtual void postFramebuffer() = 0;
virtual void renderCachedSets(const CompositionRefreshArgs&) = 0;
- virtual void chooseCompositionStrategy() = 0;
+ virtual bool chooseCompositionStrategy(
+ std::optional<android::HWComposer::DeviceRequestedChanges>*) = 0;
+ virtual void applyCompositionStrategy(
+ const std::optional<android::HWComposer::DeviceRequestedChanges>& changes) = 0;
virtual bool getSkipColorTransform() const = 0;
virtual FrameFences presentAndGetFrameFences() = 0;
virtual std::vector<LayerFE::LayerSettings> generateClientCompositionRequests(
@@ -295,6 +309,7 @@
std::vector<LayerFE::LayerSettings>& clientCompositionLayers) = 0;
virtual void setExpensiveRenderingExpected(bool enabled) = 0;
virtual void cacheClientCompositionRequests(uint32_t cacheSize) = 0;
+ virtual bool canPredictCompositionStrategy(const CompositionRefreshArgs&) = 0;
};
} // namespace compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h
index a63145a..49013e0 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h
@@ -120,16 +120,16 @@
} // namespace compositionengine
-inline std::string to_string(const android::compositionengine::ProjectionSpace& space) {
- return android::base::
- StringPrintf("ProjectionSpace(bounds = %s, content = %s, orientation = %s)",
- to_string(space.getBoundsAsRect()).c_str(),
- to_string(space.getContent()).c_str(), toCString(space.getOrientation()));
+inline std::string to_string(const compositionengine::ProjectionSpace& space) {
+ return base::StringPrintf("ProjectionSpace{bounds=%s, content=%s, orientation=%s}",
+ to_string(space.getBoundsAsRect()).c_str(),
+ to_string(space.getContent()).c_str(),
+ toCString(space.getOrientation()));
}
// Defining PrintTo helps with Google Tests.
-inline void PrintTo(const android::compositionengine::ProjectionSpace& space, ::std::ostream* os) {
+inline void PrintTo(const compositionengine::ProjectionSpace& space, std::ostream* os) {
*os << to_string(space);
}
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
index daee83b..9ee779c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
@@ -100,6 +100,9 @@
// Debugging - gets the page flip count for the RenderSurface
virtual std::uint32_t getPageFlipCount() const = 0;
+
+ // Returns true if the render surface supports client composition prediction.
+ virtual bool supportsCompositionStrategyPrediction() const = 0;
};
} // namespace compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index e12d1b4..61a0e6a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -22,6 +22,7 @@
#include <compositionengine/DisplayColorProfile.h>
#include <compositionengine/DisplayCreationArgs.h>
#include <compositionengine/RenderSurface.h>
+#include <compositionengine/impl/GpuCompositionResult.h>
#include <compositionengine/impl/Output.h>
#include <ui/PixelFormat.h>
#include <ui/Size.h>
@@ -51,11 +52,16 @@
void setReleasedLayers(const CompositionRefreshArgs&) override;
void setColorTransform(const CompositionRefreshArgs&) override;
void setColorProfile(const ColorProfile&) override;
- void chooseCompositionStrategy() override;
+
+ void beginFrame() override;
+ using DeviceRequestedChanges = android::HWComposer::DeviceRequestedChanges;
+ bool chooseCompositionStrategy(
+ std::optional<android::HWComposer::DeviceRequestedChanges>*) override;
+ void applyCompositionStrategy(const std::optional<DeviceRequestedChanges>&) override;
bool getSkipColorTransform() const override;
compositionengine::Output::FrameFences presentAndGetFrameFences() override;
void setExpensiveRenderingExpected(bool) override;
- void finishFrame(const CompositionRefreshArgs&) override;
+ void finishFrame(const CompositionRefreshArgs&, GpuCompositionResult&&) override;
// compositionengine::Display overrides
DisplayId getId() const override;
@@ -72,12 +78,11 @@
using DisplayRequests = android::HWComposer::DeviceRequestedChanges::DisplayRequests;
using LayerRequests = android::HWComposer::DeviceRequestedChanges::LayerRequests;
using ClientTargetProperty = android::HWComposer::DeviceRequestedChanges::ClientTargetProperty;
- virtual bool anyLayersRequireClientComposition() const;
virtual bool allLayersRequireClientComposition() const;
virtual void applyChangedTypesToLayers(const ChangedTypes&);
virtual void applyDisplayRequests(const DisplayRequests&);
virtual void applyLayerRequestsToLayers(const LayerRequests&);
- virtual void applyClientTargetRequests(const ClientTargetProperty&, float brightness);
+ virtual void applyClientTargetRequests(const ClientTargetProperty&);
// Internal
virtual void setConfiguration(const compositionengine::DisplayCreationArgs&);
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/GpuCompositionResult.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/GpuCompositionResult.h
new file mode 100644
index 0000000..2b1f50f
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/GpuCompositionResult.h
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/unique_fd.h>
+#include <ui/GraphicBuffer.h>
+
+namespace android::compositionengine::impl {
+
+struct GpuCompositionResult {
+ // Composition ready fence.
+ base::unique_fd fence{};
+
+ // Buffer to be used for gpu composition. If gpu composition was not successful,
+ // then we want to reuse the buffer instead of dequeuing another buffer.
+ std::shared_ptr<renderengine::ExternalTexture> buffer = nullptr;
+
+ bool bufferAvailable() const { return buffer != nullptr; };
+};
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcAsyncWorker.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcAsyncWorker.h
new file mode 100644
index 0000000..0c7da6c
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcAsyncWorker.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/thread_annotations.h>
+#include <future>
+#include <optional>
+#include <thread>
+
+#include "DisplayHardware/HWComposer.h"
+
+namespace android::compositionengine::impl {
+
+// HWC Validate call may take multiple milliseconds to complete and can account for
+// a signification amount of time in the display hotpath. This helper class allows
+// us to run the hwc validate function on a real time thread if we can predict what
+// the composition strategy will be and if composition includes client composition.
+// While the hwc validate runs, client composition is kicked off with the prediction.
+// When the worker returns with a value, the composition continues if the prediction
+// was successful otherwise the client composition is re-executed.
+//
+// Note: This does not alter the sequence between HWC and surfaceflinger.
+class HwcAsyncWorker final {
+public:
+ HwcAsyncWorker();
+ ~HwcAsyncWorker();
+ // Runs the provided function which calls hwc validate and returns the requested
+ // device changes as a future.
+ std::future<bool> send(std::function<bool()>);
+
+private:
+ std::mutex mMutex;
+ std::condition_variable mCv GUARDED_BY(mMutex);
+ bool mDone GUARDED_BY(mMutex) = false;
+ bool mTaskRequested GUARDED_BY(mMutex) = false;
+ std::packaged_task<bool()> mTask GUARDED_BY(mMutex);
+ std::thread mThread;
+ void run();
+};
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index a7a8e97..0feb9f7 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -17,9 +17,13 @@
#pragma once
#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/Output.h>
#include <compositionengine/impl/ClientCompositionRequestCache.h>
+#include <compositionengine/impl/GpuCompositionResult.h>
+#include <compositionengine/impl/HwcAsyncWorker.h>
#include <compositionengine/impl/OutputCompositionState.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
#include <compositionengine/impl/planner/Planner.h>
#include <renderengine/DisplaySettings.h>
#include <renderengine/LayerSettings.h>
@@ -92,25 +96,42 @@
void updateColorProfile(const compositionengine::CompositionRefreshArgs&) override;
void beginFrame() override;
void prepareFrame() override;
+ GpuCompositionResult prepareFrameAsync(const CompositionRefreshArgs&) override;
void devOptRepaintFlash(const CompositionRefreshArgs&) override;
- void finishFrame(const CompositionRefreshArgs&) override;
- std::optional<base::unique_fd> composeSurfaces(
- const Region&, const compositionengine::CompositionRefreshArgs& refreshArgs) override;
+ void finishFrame(const CompositionRefreshArgs&, GpuCompositionResult&&) override;
+ std::optional<base::unique_fd> composeSurfaces(const Region&,
+ const compositionengine::CompositionRefreshArgs&,
+ std::shared_ptr<renderengine::ExternalTexture>,
+ base::unique_fd&) override;
void postFramebuffer() override;
void renderCachedSets(const CompositionRefreshArgs&) override;
void cacheClientCompositionRequests(uint32_t) override;
+ bool canPredictCompositionStrategy(const CompositionRefreshArgs&) override;
+ void setPredictCompositionStrategy(bool) override;
// Testing
const ReleasedLayers& getReleasedLayersForTest() const;
void setDisplayColorProfileForTest(std::unique_ptr<compositionengine::DisplayColorProfile>);
void setRenderSurfaceForTest(std::unique_ptr<compositionengine::RenderSurface>);
bool plannerEnabled() const { return mPlanner != nullptr; }
+ virtual bool anyLayersRequireClientComposition() const;
+ virtual void updateProtectedContentState();
+ virtual bool dequeueRenderBuffer(base::unique_fd*,
+ std::shared_ptr<renderengine::ExternalTexture>*);
+ virtual std::future<bool> chooseCompositionStrategyAsync(
+ std::optional<android::HWComposer::DeviceRequestedChanges>*);
+ virtual void resetCompositionStrategy();
protected:
std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(const sp<LayerFE>&) const;
std::optional<size_t> findCurrentOutputLayerForLayer(
const sp<compositionengine::LayerFE>&) const;
- void chooseCompositionStrategy() override;
+ using DeviceRequestedChanges = android::HWComposer::DeviceRequestedChanges;
+ bool chooseCompositionStrategy(
+ std::optional<android::HWComposer::DeviceRequestedChanges>*) override {
+ return true;
+ };
+ void applyCompositionStrategy(const std::optional<DeviceRequestedChanges>&) override{};
bool getSkipColorTransform() const override;
compositionengine::Output::FrameFences presentAndGetFrameFences() override;
std::vector<LayerFE::LayerSettings> generateClientCompositionRequests(
@@ -131,6 +152,7 @@
private:
void dirtyEntireOutput();
compositionengine::OutputLayer* findLayerRequestingBackgroundComposition() const;
+ void finishPrepareFrame();
ui::Dataspace getBestDataspace(ui::Dataspace*, bool*) const;
compositionengine::Output::ColorProfile pickColorProfile(
const compositionengine::CompositionRefreshArgs&) const;
@@ -144,6 +166,7 @@
OutputLayer* mLayerRequestingBackgroundBlur = nullptr;
std::unique_ptr<ClientCompositionRequestCache> mClientCompositionRequestCache;
std::unique_ptr<planner::Planner> mPlanner;
+ std::unique_ptr<HwcAsyncWorker> mHwComposerAsyncWorker;
};
// This template factory function standardizes the implementation details of the
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index 66dd825..61be983 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -17,6 +17,7 @@
#pragma once
#include <cstdint>
+#include "aidl/android/hardware/graphics/composer3/DimmingStage.h"
#include <math/mat4.h>
#include <ui/FenceTime.h>
@@ -37,6 +38,8 @@
#include <ui/Region.h>
#include <ui/Transform.h>
+#include "DisplayHardware/HWComposer.h"
+
namespace android {
namespace compositionengine::impl {
@@ -114,6 +117,10 @@
// Current target dataspace
ui::Dataspace targetDataspace{ui::Dataspace::UNKNOWN};
+ std::optional<android::HWComposer::DeviceRequestedChanges> previousDeviceRequestedChanges{};
+
+ bool previousDeviceRequestedSuccess = false;
+
// The earliest time to send the present command to the HAL
std::chrono::steady_clock::time_point earliestPresentTime;
@@ -133,10 +140,28 @@
// Brightness of the client target, normalized to display brightness
float clientTargetBrightness{1.f};
+ // Stage in which the client target should apply dimming
+ aidl::android::hardware::graphics::composer3::DimmingStage clientTargetDimmingStage{
+ aidl::android::hardware::graphics::composer3::DimmingStage::NONE};
+
// Display brightness that will take effect this frame.
// This is slightly distinct from nits, in that nits cannot be passed to hw composer.
std::optional<float> displayBrightness = std::nullopt;
+ enum class CompositionStrategyPredictionState : uint32_t {
+ // Composition strategy prediction did not run for this frame.
+ DISABLED = 0,
+ // Composition strategy predicted successfully for this frame.
+ SUCCESS = 1,
+ // Composition strategy prediction failed for this frame.
+ FAIL = 2,
+
+ ftl_last = FAIL
+ };
+
+ CompositionStrategyPredictionState strategyPrediction =
+ CompositionStrategyPredictionState::DISABLED;
+
// Debugging
void dump(std::string& result) const;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
index a8a5380..e4cb113 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
@@ -63,6 +63,7 @@
void queueBuffer(base::unique_fd readyFence) override;
void onPresentDisplayCompleted() override;
void flip() override;
+ bool supportsCompositionStrategyPrediction() const override;
// Debugging
void dump(std::string& result) const override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
index cb00e71..29d3366 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
@@ -16,20 +16,20 @@
#pragma once
+#include <string>
+
+#include <aidl/android/hardware/graphics/common/BufferUsage.h>
+#include <aidl/android/hardware/graphics/composer3/Composition.h>
#include <android-base/strings.h>
+#include <ftl/flags.h>
+#include <math/HashCombine.h>
+
#include <compositionengine/LayerFE.h>
#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/OutputLayer.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
-#include <ftl/Flags.h>
-
-#include <string>
#include "DisplayHardware/Hal.h"
-#include "math/HashCombine.h"
-
-#include <aidl/android/hardware/graphics/common/BufferUsage.h>
-#include <aidl/android/hardware/graphics/composer3/Composition.h>
namespace std {
template <typename T>
@@ -84,13 +84,13 @@
public:
virtual ~StateInterface() = default;
- virtual Flags<LayerStateField> update(const compositionengine::OutputLayer* layer) = 0;
+ virtual ftl::Flags<LayerStateField> update(const compositionengine::OutputLayer* layer) = 0;
virtual size_t getHash() const = 0;
virtual LayerStateField getField() const = 0;
- virtual Flags<LayerStateField> getFieldIfDifferent(const StateInterface* other) const = 0;
+ virtual ftl::Flags<LayerStateField> getFieldIfDifferent(const StateInterface* other) const = 0;
virtual bool equals(const StateInterface* other) const = 0;
@@ -152,12 +152,12 @@
~OutputLayerState() override = default;
// Returns this member's field flag if it was changed
- Flags<LayerStateField> update(const compositionengine::OutputLayer* layer) override {
+ ftl::Flags<LayerStateField> update(const compositionengine::OutputLayer* layer) override {
T newValue = mReader(layer);
return update(newValue);
}
- Flags<LayerStateField> update(const T& newValue) {
+ ftl::Flags<LayerStateField> update(const T& newValue) {
if (!mEquals(mValue, newValue)) {
mValue = newValue;
mHash = {};
@@ -176,14 +176,14 @@
return *mHash;
}
- Flags<LayerStateField> getFieldIfDifferent(const StateInterface* other) const override {
+ ftl::Flags<LayerStateField> getFieldIfDifferent(const StateInterface* other) const override {
if (other->getField() != FIELD) {
return {};
}
// The early return ensures that this downcast is sound
const OutputLayerState* otherState = static_cast<const OutputLayerState*>(other);
- return *this != *otherState ? FIELD : Flags<LayerStateField>{};
+ return *this != *otherState ? FIELD : ftl::Flags<LayerStateField>{};
}
bool equals(const StateInterface* other) const override {
@@ -215,7 +215,7 @@
LayerState(compositionengine::OutputLayer* layer);
// Returns which fields were updated
- Flags<LayerStateField> update(compositionengine::OutputLayer*);
+ ftl::Flags<LayerStateField> update(compositionengine::OutputLayer*);
// Computes a hash for this LayerState.
// The hash is only computed from NonUniqueFields, and excludes GraphicBuffers since they are
@@ -224,7 +224,7 @@
// Returns the bit-set of differing fields between this LayerState and another LayerState.
// This bit-set is based on NonUniqueFields only, and excludes GraphicBuffers.
- Flags<LayerStateField> getDifferingFields(const LayerState& other) const;
+ ftl::Flags<LayerStateField> getDifferingFields(const LayerState& other) const;
compositionengine::OutputLayer* getOutputLayer() const { return mOutputLayer; }
int32_t getId() const { return mId.get(); }
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h
index ef1560e..6be6735 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h
@@ -16,6 +16,8 @@
#pragma once
+#include <ftl/flags.h>
+
#include <compositionengine/impl/planner/LayerState.h>
namespace android::compositionengine::impl::planner {
@@ -35,7 +37,7 @@
// This implies that only one layer is allowed to differ in an approximate match.
size_t differingIndex;
// Set of fields that differ for the differing layer in the approximate match.
- Flags<LayerStateField> differingFields;
+ ftl::Flags<LayerStateField> differingFields;
};
// Returns an approximate match when comparing this layer stack with the provided list of
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
index d90cc90..72e6f3b 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
@@ -41,6 +41,7 @@
MOCK_METHOD1(createDisplayColorProfile, void(const DisplayColorProfileCreationArgs&));
MOCK_METHOD1(createRenderSurface, void(const RenderSurfaceCreationArgs&));
MOCK_METHOD1(createClientCompositionCache, void(uint32_t));
+ MOCK_METHOD1(setPredictCompositionStrategy, void(bool));
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index b68b95d..fa86076 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -22,6 +22,7 @@
#include <compositionengine/Output.h>
#include <compositionengine/OutputLayer.h>
#include <compositionengine/RenderSurface.h>
+#include <compositionengine/impl/GpuCompositionResult.h>
#include <compositionengine/impl/OutputCompositionState.h>
#include <gmock/gmock.h>
@@ -99,16 +100,24 @@
MOCK_METHOD0(beginFrame, void());
MOCK_METHOD0(prepareFrame, void());
- MOCK_METHOD0(chooseCompositionStrategy, void());
+ MOCK_METHOD1(prepareFrameAsync, GpuCompositionResult(const CompositionRefreshArgs&));
+ MOCK_METHOD1(chooseCompositionStrategy,
+ bool(std::optional<android::HWComposer::DeviceRequestedChanges>*));
+ MOCK_METHOD1(chooseCompositionStrategyAsync,
+ std::future<bool>(std::optional<android::HWComposer::DeviceRequestedChanges>*));
+ MOCK_METHOD1(applyCompositionStrategy,
+ void(const std::optional<android::HWComposer::DeviceRequestedChanges>&));
MOCK_METHOD1(devOptRepaintFlash, void(const compositionengine::CompositionRefreshArgs&));
- MOCK_METHOD1(finishFrame, void(const compositionengine::CompositionRefreshArgs&));
+ MOCK_METHOD2(finishFrame,
+ void(const compositionengine::CompositionRefreshArgs&, GpuCompositionResult&&));
- MOCK_METHOD2(composeSurfaces,
+ MOCK_METHOD4(composeSurfaces,
std::optional<base::unique_fd>(
const Region&,
- const compositionengine::CompositionRefreshArgs& refreshArgs));
+ const compositionengine::CompositionRefreshArgs& refreshArgs,
+ std::shared_ptr<renderengine::ExternalTexture>, base::unique_fd&));
MOCK_CONST_METHOD0(getSkipColorTransform, bool());
MOCK_METHOD0(postFramebuffer, void());
@@ -121,6 +130,8 @@
void(const Region&, std::vector<LayerFE::LayerSettings>&));
MOCK_METHOD1(setExpensiveRenderingExpected, void(bool));
MOCK_METHOD1(cacheClientCompositionRequests, void(uint32_t));
+ MOCK_METHOD1(canPredictCompositionStrategy, bool(const CompositionRefreshArgs&));
+ MOCK_METHOD1(setPredictCompositionStrategy, void(bool));
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
index fe858c2..e12aebb 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -45,6 +45,7 @@
MOCK_METHOD0(flip, void());
MOCK_CONST_METHOD1(dump, void(std::string& result));
MOCK_CONST_METHOD0(getPageFlipCount, std::uint32_t());
+ MOCK_CONST_METHOD0(supportsCompositionStrategyPrediction, bool());
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 2165e1d..b79b46b 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -131,15 +131,11 @@
}
void Display::dump(std::string& out) const {
- using android::base::StringAppendF;
+ const char* const type = isVirtual() ? "virtual" : "physical";
+ base::StringAppendF(&out, "Display %s (%s, \"%s\")", to_string(mId).c_str(), type,
+ getName().c_str());
- StringAppendF(&out, " Composition Display State: [\"%s\"]", getName().c_str());
-
- out.append("\n ");
- dumpVal(out, "isVirtual", isVirtual());
- dumpVal(out, "DisplayId", to_string(mId));
- out.append("\n");
-
+ out.append("\n Composition Display State:\n");
Output::dumpBase(out);
}
@@ -207,16 +203,8 @@
setReleasedLayers(std::move(releasedLayers));
}
-void Display::chooseCompositionStrategy() {
- ATRACE_CALL();
- ALOGV(__FUNCTION__);
-
- if (mIsDisconnected) {
- return;
- }
-
- // Default to the base settings -- client composition only.
- Output::chooseCompositionStrategy();
+void Display::beginFrame() {
+ Output::beginFrame();
// If we don't have a HWC display, then we are done.
const auto halDisplayId = HalDisplayId::tryCast(mId);
@@ -224,43 +212,66 @@
return;
}
- // Get any composition changes requested by the HWC device, and apply them.
- std::optional<android::HWComposer::DeviceRequestedChanges> changes;
auto& hwc = getCompositionEngine().getHwComposer();
if (const auto physicalDisplayId = PhysicalDisplayId::tryCast(*halDisplayId);
physicalDisplayId && getState().displayBrightness) {
const status_t result =
hwc.setDisplayBrightness(*physicalDisplayId, *getState().displayBrightness,
+ getState().displayBrightnessNits,
Hwc2::Composer::DisplayBrightnessOptions{
.applyImmediately = false})
.get();
ALOGE_IF(result != NO_ERROR, "setDisplayBrightness failed for %s: %d, (%s)",
getName().c_str(), result, strerror(-result));
}
+ // Clear out the display brightness now that it's been communicated to composer.
+ editState().displayBrightness.reset();
+}
+bool Display::chooseCompositionStrategy(
+ std::optional<android::HWComposer::DeviceRequestedChanges>* outChanges) {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ if (mIsDisconnected) {
+ return false;
+ }
+
+ // If we don't have a HWC display, then we are done.
+ const auto halDisplayId = HalDisplayId::tryCast(mId);
+ if (!halDisplayId) {
+ return false;
+ }
+
+ // Get any composition changes requested by the HWC device, and apply them.
+ std::optional<android::HWComposer::DeviceRequestedChanges> changes;
+ auto& hwc = getCompositionEngine().getHwComposer();
if (status_t result =
hwc.getDeviceCompositionChanges(*halDisplayId, anyLayersRequireClientComposition(),
getState().earliestPresentTime,
getState().previousPresentFence,
- getState().expectedPresentTime, &changes);
+ getState().expectedPresentTime, outChanges);
result != NO_ERROR) {
ALOGE("chooseCompositionStrategy failed for %s: %d (%s)", getName().c_str(), result,
strerror(-result));
- return;
+ return false;
}
+
+ return true;
+}
+
+void Display::applyCompositionStrategy(const std::optional<DeviceRequestedChanges>& changes) {
if (changes) {
applyChangedTypesToLayers(changes->changedTypes);
applyDisplayRequests(changes->displayRequests);
applyLayerRequestsToLayers(changes->layerRequests);
- applyClientTargetRequests(changes->clientTargetProperty, changes->clientTargetBrightness);
+ applyClientTargetRequests(changes->clientTargetProperty);
}
// Determine what type of composition we are doing from the final state
auto& state = editState();
state.usesClientComposition = anyLayersRequireClientComposition();
state.usesDeviceComposition = !allLayersRequireClientComposition();
- // Clear out the display brightness now that it's been communicated to composer.
- state.displayBrightness.reset();
}
bool Display::getSkipColorTransform() const {
@@ -273,12 +284,6 @@
return hwc.hasCapability(Capability::SKIP_CLIENT_COLOR_TRANSFORM);
}
-bool Display::anyLayersRequireClientComposition() const {
- const auto layers = getOutputLayersOrderedByZ();
- return std::any_of(layers.begin(), layers.end(),
- [](const auto& layer) { return layer->requiresClientComposition(); });
-}
-
bool Display::allLayersRequireClientComposition() const {
const auto layers = getOutputLayersOrderedByZ();
return std::all_of(layers.begin(), layers.end(),
@@ -327,16 +332,19 @@
}
}
-void Display::applyClientTargetRequests(const ClientTargetProperty& clientTargetProperty,
- float brightness) {
- if (clientTargetProperty.dataspace == ui::Dataspace::UNKNOWN) {
+void Display::applyClientTargetRequests(const ClientTargetProperty& clientTargetProperty) {
+ if (static_cast<ui::Dataspace>(clientTargetProperty.clientTargetProperty.dataspace) ==
+ ui::Dataspace::UNKNOWN) {
return;
}
- editState().dataspace = clientTargetProperty.dataspace;
- editState().clientTargetBrightness = brightness;
- getRenderSurface()->setBufferDataspace(clientTargetProperty.dataspace);
- getRenderSurface()->setBufferPixelFormat(clientTargetProperty.pixelFormat);
+ editState().dataspace =
+ static_cast<ui::Dataspace>(clientTargetProperty.clientTargetProperty.dataspace);
+ editState().clientTargetBrightness = clientTargetProperty.brightness;
+ editState().clientTargetDimmingStage = clientTargetProperty.dimmingStage;
+ getRenderSurface()->setBufferDataspace(editState().dataspace);
+ getRenderSurface()->setBufferPixelFormat(
+ static_cast<ui::PixelFormat>(clientTargetProperty.clientTargetProperty.pixelFormat));
}
compositionengine::Output::FrameFences Display::presentAndGetFrameFences() {
@@ -376,7 +384,8 @@
}
}
-void Display::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs) {
+void Display::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs,
+ GpuCompositionResult&& result) {
// We only need to actually compose the display if:
// 1) It is being handled by hardware composer, which may need this to
// keep its virtual display state machine in sync, or
@@ -386,7 +395,7 @@
return;
}
- impl::Output::finishFrame(refreshArgs);
+ impl::Output::finishFrame(refreshArgs, std::move(result));
}
} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp b/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp
index db6d4f2..28900af 100644
--- a/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp
@@ -20,4 +20,8 @@
DisplaySurface::~DisplaySurface() = default;
+bool DisplaySurface::supportsCompositionStrategyPrediction() const {
+ return true;
+}
+
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
index 01c368d..290c710 100644
--- a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
@@ -89,7 +89,6 @@
void dumpVal(std::string& out, const char* name, const ui::Transform& transform) {
transform.dump(out, name);
- out.append(" ");
}
void dumpVal(std::string& out, const char* name, const mat4& tr) {
@@ -99,7 +98,7 @@
"[%0.3f,%0.3f,%0.3f,%0.3f]"
"[%0.3f,%0.3f,%0.3f,%0.3f]"
"[%0.3f,%0.3f,%0.3f,%0.3f]"
- "[%0.3f,%0.3f,%0.3f,%0.3f]]",
+ "[%0.3f,%0.3f,%0.3f,%0.3f]] ",
name,
tr[0][0], tr[1][0], tr[2][0], tr[3][0],
tr[0][1], tr[1][1], tr[2][1], tr[3][1],
@@ -109,9 +108,9 @@
}
void dumpVal(std::string& out, const char* name, const StretchEffect& effect) {
- StringAppendF(&out, "%s={ width =%f, height = %f, vec=(%f, %f), max=(%f, %f) } ", name,
- effect.width, effect.height,
- effect.vectorX, effect.vectorY, effect.maxAmountX, effect.maxAmountY);
+ StringAppendF(&out, "%s={width=%f, height=%f, vec=(%f, %f), max=(%f, %f)} ", name, effect.width,
+ effect.height, effect.vectorX, effect.vectorY, effect.maxAmountX,
+ effect.maxAmountY);
}
} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/HwcAsyncWorker.cpp b/services/surfaceflinger/CompositionEngine/src/HwcAsyncWorker.cpp
new file mode 100644
index 0000000..6086f0b
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/HwcAsyncWorker.cpp
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#include <compositionengine/impl/HwcAsyncWorker.h>
+#include <processgroup/sched_policy.h>
+#include <pthread.h>
+#include <sched.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <system/thread_defs.h>
+
+#include <android-base/thread_annotations.h>
+#include <cutils/sched_policy.h>
+
+namespace android::compositionengine::impl {
+
+HwcAsyncWorker::HwcAsyncWorker() {
+ mThread = std::thread(&HwcAsyncWorker::run, this);
+ pthread_setname_np(mThread.native_handle(), "HwcAsyncWorker");
+}
+
+HwcAsyncWorker::~HwcAsyncWorker() {
+ {
+ std::scoped_lock lock(mMutex);
+ mDone = true;
+ mCv.notify_all();
+ }
+ if (mThread.joinable()) {
+ mThread.join();
+ }
+}
+std::future<bool> HwcAsyncWorker::send(std::function<bool()> task) {
+ std::unique_lock<std::mutex> lock(mMutex);
+ android::base::ScopedLockAssertion assumeLock(mMutex);
+ mTask = std::packaged_task<bool()>([task = std::move(task)]() { return task(); });
+ mTaskRequested = true;
+ mCv.notify_one();
+ return mTask.get_future();
+}
+
+void HwcAsyncWorker::run() {
+ set_sched_policy(0, SP_FOREGROUND);
+ struct sched_param param = {0};
+ param.sched_priority = 2;
+ sched_setscheduler(gettid(), SCHED_FIFO, ¶m);
+
+ std::unique_lock<std::mutex> lock(mMutex);
+ android::base::ScopedLockAssertion assumeLock(mMutex);
+ while (!mDone) {
+ mCv.wait(lock);
+ if (mTaskRequested && mTask.valid()) {
+ mTask();
+ mTaskRequested = false;
+ }
+ }
+}
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
index ff7d430..6631a27 100644
--- a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
@@ -121,6 +121,7 @@
dumpVal(out, "isColorspaceAgnostic", isColorspaceAgnostic);
dumpVal(out, "dataspace", toString(dataspace), dataspace);
dumpVal(out, "hdr metadata types", hdrMetadata.validTypes);
+ dumpVal(out, "dimming enabled", dimmingEnabled);
dumpVal(out, "colorTransform", colorTransform);
out.append("\n");
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 4e67a63..ec86731 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -22,6 +22,7 @@
#include <compositionengine/LayerFE.h>
#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/RenderSurface.h>
+#include <compositionengine/impl/HwcAsyncWorker.h>
#include <compositionengine/impl/Output.h>
#include <compositionengine/impl/OutputCompositionState.h>
#include <compositionengine/impl/OutputLayer.h>
@@ -57,7 +58,8 @@
Output::~Output() = default;
namespace impl {
-
+using CompositionStrategyPredictionState =
+ OutputCompositionState::CompositionStrategyPredictionState;
namespace {
template <typename T>
@@ -292,17 +294,15 @@
}
void Output::dump(std::string& out) const {
- using android::base::StringAppendF;
-
- StringAppendF(&out, " Composition Output State: [\"%s\"]", mName.c_str());
-
- out.append("\n ");
+ base::StringAppendF(&out, "Output \"%s\"", mName.c_str());
+ out.append("\n Composition Output State:\n");
dumpBase(out);
}
void Output::dumpBase(std::string& out) const {
dumpState(out);
+ out += '\n';
if (mDisplayColorProfile) {
mDisplayColorProfile->dump(out);
@@ -310,13 +310,15 @@
out.append(" No display color profile!\n");
}
+ out += '\n';
+
if (mRenderSurface) {
mRenderSurface->dump(out);
} else {
out.append(" No render surface!\n");
}
- android::base::StringAppendF(&out, "\n %zu Layers\n", getOutputLayerCount());
+ base::StringAppendF(&out, "\n %zu Layers\n", getOutputLayerCount());
for (const auto* outputLayer : getOutputLayersOrderedByZ()) {
if (!outputLayer) {
continue;
@@ -327,7 +329,7 @@
void Output::dumpPlannerInfo(const Vector<String16>& args, std::string& out) const {
if (!mPlanner) {
- base::StringAppendF(&out, "Planner is disabled\n");
+ out.append("Planner is disabled\n");
return;
}
base::StringAppendF(&out, "Planner info for display [%s]\n", mName.c_str());
@@ -434,9 +436,17 @@
writeCompositionState(refreshArgs);
setColorTransform(refreshArgs);
beginFrame();
- prepareFrame();
+
+ GpuCompositionResult result;
+ const bool predictCompositionStrategy = canPredictCompositionStrategy(refreshArgs);
+ if (predictCompositionStrategy) {
+ result = prepareFrameAsync(refreshArgs);
+ } else {
+ prepareFrame();
+ }
+
devOptRepaintFlash(refreshArgs);
- finishFrame(refreshArgs);
+ finishFrame(refreshArgs, std::move(result));
postFramebuffer();
renderCachedSets(refreshArgs);
}
@@ -953,19 +963,74 @@
ATRACE_CALL();
ALOGV(__FUNCTION__);
- const auto& outputState = getState();
+ auto& outputState = editState();
if (!outputState.isEnabled) {
return;
}
- chooseCompositionStrategy();
+ std::optional<android::HWComposer::DeviceRequestedChanges> changes;
+ bool success = chooseCompositionStrategy(&changes);
+ resetCompositionStrategy();
+ outputState.strategyPrediction = CompositionStrategyPredictionState::DISABLED;
+ outputState.previousDeviceRequestedChanges = changes;
+ outputState.previousDeviceRequestedSuccess = success;
+ if (success) {
+ applyCompositionStrategy(changes);
+ }
+ finishPrepareFrame();
+}
- if (mPlanner) {
- mPlanner->reportFinalPlan(getOutputLayersOrderedByZ());
+std::future<bool> Output::chooseCompositionStrategyAsync(
+ std::optional<android::HWComposer::DeviceRequestedChanges>* changes) {
+ return mHwComposerAsyncWorker->send(
+ [&, changes]() { return chooseCompositionStrategy(changes); });
+}
+
+GpuCompositionResult Output::prepareFrameAsync(const CompositionRefreshArgs& refreshArgs) {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+ auto& state = editState();
+ const auto& previousChanges = state.previousDeviceRequestedChanges;
+ std::optional<android::HWComposer::DeviceRequestedChanges> changes;
+ resetCompositionStrategy();
+ auto hwcResult = chooseCompositionStrategyAsync(&changes);
+ if (state.previousDeviceRequestedSuccess) {
+ applyCompositionStrategy(previousChanges);
+ }
+ finishPrepareFrame();
+
+ base::unique_fd bufferFence;
+ std::shared_ptr<renderengine::ExternalTexture> buffer;
+ updateProtectedContentState();
+ const bool dequeueSucceeded = dequeueRenderBuffer(&bufferFence, &buffer);
+ GpuCompositionResult compositionResult;
+ if (dequeueSucceeded) {
+ std::optional<base::unique_fd> optFd =
+ composeSurfaces(Region::INVALID_REGION, refreshArgs, buffer, bufferFence);
+ if (optFd) {
+ compositionResult.fence = std::move(*optFd);
+ }
}
- mRenderSurface->prepareFrame(outputState.usesClientComposition,
- outputState.usesDeviceComposition);
+ auto chooseCompositionSuccess = hwcResult.get();
+ const bool predictionSucceeded = dequeueSucceeded && changes == previousChanges;
+ state.strategyPrediction = predictionSucceeded ? CompositionStrategyPredictionState::SUCCESS
+ : CompositionStrategyPredictionState::FAIL;
+ if (!predictionSucceeded) {
+ ATRACE_NAME("CompositionStrategyPredictionMiss");
+ resetCompositionStrategy();
+ if (chooseCompositionSuccess) {
+ applyCompositionStrategy(changes);
+ }
+ finishPrepareFrame();
+ // Track the dequeued buffer to reuse so we don't need to dequeue another one.
+ compositionResult.buffer = buffer;
+ } else {
+ ATRACE_NAME("CompositionStrategyPredictionHit");
+ }
+ state.previousDeviceRequestedChanges = std::move(changes);
+ state.previousDeviceRequestedSuccess = chooseCompositionSuccess;
+ return compositionResult;
}
void Output::devOptRepaintFlash(const compositionengine::CompositionRefreshArgs& refreshArgs) {
@@ -975,7 +1040,11 @@
if (getState().isEnabled) {
if (const auto dirtyRegion = getDirtyRegion(); !dirtyRegion.isEmpty()) {
- static_cast<void>(composeSurfaces(dirtyRegion, refreshArgs));
+ base::unique_fd bufferFence;
+ std::shared_ptr<renderengine::ExternalTexture> buffer;
+ updateProtectedContentState();
+ dequeueRenderBuffer(&bufferFence, &buffer);
+ static_cast<void>(composeSurfaces(dirtyRegion, refreshArgs, buffer, bufferFence));
mRenderSurface->queueBuffer(base::unique_fd());
}
}
@@ -987,17 +1056,33 @@
prepareFrame();
}
-void Output::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs) {
+void Output::finishFrame(const CompositionRefreshArgs& refreshArgs, GpuCompositionResult&& result) {
ATRACE_CALL();
ALOGV(__FUNCTION__);
-
- if (!getState().isEnabled) {
+ const auto& outputState = getState();
+ if (!outputState.isEnabled) {
return;
}
- // Repaint the framebuffer (if needed), getting the optional fence for when
- // the composition completes.
- auto optReadyFence = composeSurfaces(Region::INVALID_REGION, refreshArgs);
+ std::optional<base::unique_fd> optReadyFence;
+ std::shared_ptr<renderengine::ExternalTexture> buffer;
+ base::unique_fd bufferFence;
+ if (outputState.strategyPrediction == CompositionStrategyPredictionState::SUCCESS) {
+ optReadyFence = std::move(result.fence);
+ } else {
+ if (result.bufferAvailable()) {
+ buffer = std::move(result.buffer);
+ bufferFence = std::move(result.fence);
+ } else {
+ updateProtectedContentState();
+ if (!dequeueRenderBuffer(&bufferFence, &buffer)) {
+ return;
+ }
+ }
+ // Repaint the framebuffer (if needed), getting the optional fence for when
+ // the composition completes.
+ optReadyFence = composeSurfaces(Region::INVALID_REGION, refreshArgs, buffer, bufferFence);
+ }
if (!optReadyFence) {
return;
}
@@ -1006,16 +1091,8 @@
mRenderSurface->queueBuffer(std::move(*optReadyFence));
}
-std::optional<base::unique_fd> Output::composeSurfaces(
- const Region& debugRegion, const compositionengine::CompositionRefreshArgs& refreshArgs) {
- ATRACE_CALL();
- ALOGV(__FUNCTION__);
-
+void Output::updateProtectedContentState() {
const auto& outputState = getState();
- OutputCompositionState& outputCompositionState = editState();
- const TracedOrdinal<bool> hasClientComposition = {"hasClientComposition",
- outputState.usesClientComposition};
-
auto& renderEngine = getCompositionEngine().getRenderEngine();
const bool supportsProtectedContent = renderEngine.supportsProtectedContent();
@@ -1037,29 +1114,48 @@
} else if (!outputState.isSecure && renderEngine.isProtected()) {
renderEngine.useProtectedContext(false);
}
+}
- base::unique_fd fd;
-
- std::shared_ptr<renderengine::ExternalTexture> tex;
+bool Output::dequeueRenderBuffer(base::unique_fd* bufferFence,
+ std::shared_ptr<renderengine::ExternalTexture>* tex) {
+ const auto& outputState = getState();
// If we aren't doing client composition on this output, but do have a
// flipClientTarget request for this frame on this output, we still need to
// dequeue a buffer.
- if (hasClientComposition || outputState.flipClientTarget) {
- tex = mRenderSurface->dequeueBuffer(&fd);
- if (tex == nullptr) {
+ if (outputState.usesClientComposition || outputState.flipClientTarget) {
+ *tex = mRenderSurface->dequeueBuffer(bufferFence);
+ if (*tex == nullptr) {
ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
"client composition for this frame",
mName.c_str());
- return {};
+ return false;
}
}
+ return true;
+}
+std::optional<base::unique_fd> Output::composeSurfaces(
+ const Region& debugRegion, const compositionengine::CompositionRefreshArgs& refreshArgs,
+ std::shared_ptr<renderengine::ExternalTexture> tex, base::unique_fd& fd) {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ const auto& outputState = getState();
+ const TracedOrdinal<bool> hasClientComposition = {"hasClientComposition",
+ outputState.usesClientComposition};
if (!hasClientComposition) {
setExpensiveRenderingExpected(false);
return base::unique_fd();
}
+ if (tex == nullptr) {
+ ALOGW("Buffer not valid for display [%s], bailing out of "
+ "client composition for this frame",
+ mName.c_str());
+ return {};
+ }
+
ALOGV("hasClientComposition");
renderengine::DisplaySettings clientCompositionDisplay;
@@ -1080,6 +1176,10 @@
mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance();
clientCompositionDisplay.targetLuminanceNits =
outputState.clientTargetBrightness * outputState.displayBrightnessNits;
+ clientCompositionDisplay.dimmingStage = outputState.clientTargetDimmingStage;
+ clientCompositionDisplay.renderIntent =
+ static_cast<aidl::android::hardware::graphics::composer3::RenderIntent>(
+ outputState.renderIntent);
// Compute the global color transform matrix.
clientCompositionDisplay.colorTransform = outputState.colorTransformMatrix;
@@ -1087,6 +1187,8 @@
outputState.usesDeviceComposition || getSkipColorTransform();
// Generate the client composition requests for the layers on this output.
+ auto& renderEngine = getCompositionEngine().getRenderEngine();
+ const bool supportsProtectedContent = renderEngine.supportsProtectedContent();
std::vector<LayerFE*> clientCompositionLayersFE;
std::vector<LayerFE::LayerSettings> clientCompositionLayers =
generateClientCompositionRequests(supportsProtectedContent,
@@ -1094,16 +1196,19 @@
clientCompositionLayersFE);
appendRegionFlashRequests(debugRegion, clientCompositionLayers);
+ OutputCompositionState& outputCompositionState = editState();
// Check if the client composition requests were rendered into the provided graphic buffer. If
// so, we can reuse the buffer and avoid client composition.
if (mClientCompositionRequestCache) {
if (mClientCompositionRequestCache->exists(tex->getBuffer()->getId(),
clientCompositionDisplay,
clientCompositionLayers)) {
+ ATRACE_NAME("ClientCompositionCacheHit");
outputCompositionState.reusedClientComposition = true;
setExpensiveRenderingExpected(false);
return base::unique_fd();
}
+ ATRACE_NAME("ClientCompositionCacheMiss");
mClientCompositionRequestCache->add(tex->getBuffer()->getId(), clientCompositionDisplay,
clientCompositionLayers);
}
@@ -1355,7 +1460,7 @@
outputState.dirtyRegion.set(outputState.displaySpace.getBoundsAsRect());
}
-void Output::chooseCompositionStrategy() {
+void Output::resetCompositionStrategy() {
// The base output implementation can only do client composition
auto& outputState = editState();
outputState.usesClientComposition = true;
@@ -1375,5 +1480,63 @@
return result;
}
+void Output::setPredictCompositionStrategy(bool predict) {
+ if (predict) {
+ mHwComposerAsyncWorker = std::make_unique<HwcAsyncWorker>();
+ } else {
+ mHwComposerAsyncWorker.reset(nullptr);
+ }
+}
+
+bool Output::canPredictCompositionStrategy(const CompositionRefreshArgs& refreshArgs) {
+ if (!getState().isEnabled || !mHwComposerAsyncWorker) {
+ ALOGV("canPredictCompositionStrategy disabled");
+ return false;
+ }
+
+ if (!getState().previousDeviceRequestedChanges) {
+ ALOGV("canPredictCompositionStrategy previous changes not available");
+ return false;
+ }
+
+ if (!mRenderSurface->supportsCompositionStrategyPrediction()) {
+ ALOGV("canPredictCompositionStrategy surface does not support");
+ return false;
+ }
+
+ if (refreshArgs.devOptFlashDirtyRegionsDelay) {
+ ALOGV("canPredictCompositionStrategy devOptFlashDirtyRegionsDelay");
+ return false;
+ }
+
+ // If no layer uses clientComposition, then don't predict composition strategy
+ // because we have less work to do in parallel.
+ if (!anyLayersRequireClientComposition()) {
+ ALOGV("canPredictCompositionStrategy no layer uses clientComposition");
+ return false;
+ }
+
+ if (!refreshArgs.updatingOutputGeometryThisFrame) {
+ return true;
+ }
+
+ ALOGV("canPredictCompositionStrategy updatingOutputGeometryThisFrame");
+ return false;
+}
+
+bool Output::anyLayersRequireClientComposition() const {
+ const auto layers = getOutputLayersOrderedByZ();
+ return std::any_of(layers.begin(), layers.end(),
+ [](const auto& layer) { return layer->requiresClientComposition(); });
+}
+
+void Output::finishPrepareFrame() {
+ const auto& state = getState();
+ if (mPlanner) {
+ mPlanner->reportFinalPlan(getOutputLayersOrderedByZ());
+ }
+ mRenderSurface->prepareFrame(state.usesClientComposition, state.usesDeviceComposition);
+}
+
} // namespace impl
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
index 482250a..3b85e3b 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <ftl/enum.h>
+
#include <compositionengine/impl/DumpHelpers.h>
#include <compositionengine/impl/OutputCompositionState.h>
@@ -23,18 +25,19 @@
out.append(" ");
dumpVal(out, "isEnabled", isEnabled);
dumpVal(out, "isSecure", isSecure);
-
- dumpVal(out, "usesClientComposition", usesClientComposition);
dumpVal(out, "usesDeviceComposition", usesDeviceComposition);
+
+ out.append("\n ");
+ dumpVal(out, "usesClientComposition", usesClientComposition);
dumpVal(out, "flipClientTarget", flipClientTarget);
dumpVal(out, "reusedClientComposition", reusedClientComposition);
- dumpVal(out, "layerFilter", layerFilter);
out.append("\n ");
-
+ dumpVal(out, "layerFilter", layerFilter);
+ out.append("\n ");
dumpVal(out, "transform", transform);
- out.append("\n ");
+ out.append(" "); // ui::Transform::dump appends EOL.
dumpVal(out, "layerStackSpace", to_string(layerStackSpace));
out.append("\n ");
dumpVal(out, "framebufferSpace", to_string(framebufferSpace));
@@ -46,18 +49,24 @@
dumpVal(out, "needsFiltering", needsFiltering);
out.append("\n ");
-
dumpVal(out, "colorMode", toString(colorMode), colorMode);
dumpVal(out, "renderIntent", toString(renderIntent), renderIntent);
dumpVal(out, "dataspace", toString(dataspace), dataspace);
+ dumpVal(out, "targetDataspace", toString(targetDataspace), targetDataspace);
+
+ out.append("\n ");
dumpVal(out, "colorTransformMatrix", colorTransformMatrix);
- dumpVal(out, "target dataspace", toString(targetDataspace), targetDataspace);
+
+ out.append("\n ");
dumpVal(out, "displayBrightnessNits", displayBrightnessNits);
dumpVal(out, "sdrWhitePointNits", sdrWhitePointNits);
dumpVal(out, "clientTargetBrightness", clientTargetBrightness);
dumpVal(out, "displayBrightness", displayBrightness);
- out.append("\n");
+ out.append("\n ");
+ dumpVal(out, "compositionStrategyPredictionState", ftl::enum_string(strategyPrediction));
+
+ out += '\n';
}
} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 723593d..3289d55 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -324,9 +324,10 @@
// For hdr content, treat the white point as the display brightness - HDR content should not be
// boosted or dimmed.
+ // If the layer explicitly requests to disable dimming, then don't dim either.
if (isHdrDataspace(state.dataspace) ||
getOutput().getState().displayBrightnessNits == getOutput().getState().sdrWhitePointNits ||
- getOutput().getState().displayBrightnessNits == 0.f) {
+ getOutput().getState().displayBrightnessNits == 0.f || !layerFEState->dimmingEnabled) {
state.dimmingRatio = 1.f;
state.whitePointNits = getOutput().getState().displayBrightnessNits;
} else {
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index 12c2c8e..5a3af7b 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -289,5 +289,9 @@
return mTexture;
}
+bool RenderSurface::supportsCompositionStrategyPrediction() const {
+ return mDisplaySurface->supportsCompositionStrategyPrediction();
+}
+
} // namespace impl
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
index c79ca0d..f439caf 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
@@ -41,7 +41,7 @@
update(layer);
}
-Flags<LayerStateField> LayerState::update(compositionengine::OutputLayer* layer) {
+ftl::Flags<LayerStateField> LayerState::update(compositionengine::OutputLayer* layer) {
ALOGE_IF(mOutputLayer != layer && layer->getLayerFE().getSequence() != mId.get(),
"[%s] Expected mOutputLayer ID to never change: %d, %d", __func__,
layer->getLayerFE().getSequence(), mId.get());
@@ -50,7 +50,7 @@
// same, i.e., the LayerFE is the same. An example use-case is screen rotation.
mOutputLayer = layer;
- Flags<LayerStateField> differences;
+ ftl::Flags<LayerStateField> differences;
// Update the unique fields as well, since we have to set them at least
// once from the OutputLayer
@@ -76,8 +76,8 @@
return hash;
}
-Flags<LayerStateField> LayerState::getDifferingFields(const LayerState& other) const {
- Flags<LayerStateField> differences;
+ftl::Flags<LayerStateField> LayerState::getDifferingFields(const LayerState& other) const {
+ ftl::Flags<LayerStateField> differences;
auto myFields = getNonUniqueFields();
auto otherFields = other.getNonUniqueFields();
for (size_t i = 0; i < myFields.size(); ++i) {
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
index 74d2701..c8413eb 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
@@ -97,7 +97,7 @@
if (const auto layerEntry = mPreviousLayers.find(id); layerEntry != mPreviousLayers.end()) {
// Track changes from previous info
LayerState& state = layerEntry->second;
- Flags<LayerStateField> differences = state.update(layer);
+ ftl::Flags<LayerStateField> differences = state.update(layer);
if (differences.get() == 0) {
state.incrementFramesSinceBufferUpdate();
} else {
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp
index 2d53583..2fc029f 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp
@@ -57,7 +57,7 @@
return std::nullopt;
}
- Flags<LayerStateField> differingFields = mLayers[i].getDifferingFields(*other[i]);
+ ftl::Flags<LayerStateField> differingFields = mLayers[i].getDifferingFields(*other[i]);
// If we don't find an approximate match on this layer, then the LayerStacks differ
// by too much, so return nothing
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 5cc0f97..0e5a7b6 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -30,7 +30,9 @@
#include <compositionengine/mock/OutputLayer.h>
#include <compositionengine/mock/RenderSurface.h>
#include <gtest/gtest.h>
+#include <renderengine/mock/FakeExternalTexture.h>
#include <renderengine/mock/RenderEngine.h>
+
#include <ui/Rect.h>
#include <ui/StaticDisplayInfo.h>
@@ -43,6 +45,7 @@
using aidl::android::hardware::graphics::composer3::Capability;
using aidl::android::hardware::graphics::composer3::Composition;
+using aidl::android::hardware::graphics::composer3::DimmingStage;
namespace android::compositionengine {
namespace {
@@ -113,8 +116,9 @@
return mCompositionEngine;
};
+ size_t getOutputLayerCount() const override { return 1u; }
+
// Mock implementation overrides
- MOCK_CONST_METHOD0(getOutputLayerCount, size_t());
MOCK_CONST_METHOD1(getOutputLayerOrderedByZByIndex,
compositionengine::OutputLayer*(size_t));
MOCK_METHOD2(ensureOutputLayer,
@@ -197,6 +201,26 @@
std::shared_ptr<Display> mDisplay =
createPartialMockDisplay<Display>(mCompositionEngine,
getDisplayCreationArgsForPhysicalDisplay());
+
+ android::HWComposer::DeviceRequestedChanges mDeviceRequestedChanges{
+ {{nullptr, Composition::CLIENT}},
+ hal::DisplayRequest::FLIP_CLIENT_TARGET,
+ {{nullptr, hal::LayerRequest::CLEAR_CLIENT_TARGET}},
+ {DEFAULT_DISPLAY_ID.value,
+ {aidl::android::hardware::graphics::common::PixelFormat::RGBA_8888,
+ aidl::android::hardware::graphics::common::Dataspace::UNKNOWN},
+ -1.f,
+ DimmingStage::NONE},
+ };
+
+ void chooseCompositionStrategy(Display* display) {
+ std::optional<android::HWComposer::DeviceRequestedChanges> changes;
+ bool success = display->chooseCompositionStrategy(&changes);
+ display->resetCompositionStrategy();
+ if (success) {
+ display->applyCompositionStrategy(changes);
+ }
+ }
};
struct FullDisplayImplTestCommon : public DisplayTestCommon {
@@ -213,6 +237,11 @@
std::unique_ptr<compositionengine::OutputLayer>(mLayer2.outputLayer));
mDisplay->injectOutputLayerForTest(
std::unique_ptr<compositionengine::OutputLayer>(mLayer3.outputLayer));
+ mResultWithBuffer.buffer = std::make_shared<
+ renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/,
+ 1ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0ULL /*usage*/);
}
Layer mLayer1;
@@ -221,6 +250,8 @@
StrictMock<HWC2::mock::Layer> hwc2LayerUnknown;
std::shared_ptr<Display> mDisplay =
createDisplay<Display>(mCompositionEngine, getDisplayCreationArgsForPhysicalDisplay());
+ impl::GpuCompositionResult mResultWithBuffer;
+ impl::GpuCompositionResult mResultWithoutBuffer;
};
/*
@@ -553,7 +584,7 @@
createPartialMockDisplay<Display>(mCompositionEngine, args);
EXPECT_TRUE(GpuVirtualDisplayId::tryCast(gpuDisplay->getId()));
- gpuDisplay->chooseCompositionStrategy();
+ chooseCompositionStrategy(gpuDisplay.get());
auto& state = gpuDisplay->getState();
EXPECT_TRUE(state.usesClientComposition);
@@ -566,11 +597,12 @@
getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), false, _, _, _, _))
.WillOnce(Return(INVALID_OPERATION));
- mDisplay->chooseCompositionStrategy();
+ chooseCompositionStrategy(mDisplay.get());
auto& state = mDisplay->getState();
EXPECT_TRUE(state.usesClientComposition);
EXPECT_FALSE(state.usesDeviceComposition);
+ EXPECT_FALSE(state.previousDeviceRequestedChanges.has_value());
}
TEST_F(DisplayChooseCompositionStrategyTest, normalOperation) {
@@ -587,10 +619,16 @@
EXPECT_CALL(mHwComposer,
getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _))
- .WillOnce(Return(NO_ERROR));
+ .WillOnce(testing::DoAll(testing::SetArgPointee<5>(mDeviceRequestedChanges),
+ Return(NO_ERROR)));
+ EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(mDeviceRequestedChanges.changedTypes))
+ .Times(1);
+ EXPECT_CALL(*mDisplay, applyDisplayRequests(mDeviceRequestedChanges.displayRequests)).Times(1);
+ EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(mDeviceRequestedChanges.layerRequests))
+ .Times(1);
EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false));
- mDisplay->chooseCompositionStrategy();
+ chooseCompositionStrategy(mDisplay.get());
auto& state = mDisplay->getState();
EXPECT_FALSE(state.usesClientComposition);
@@ -602,42 +640,25 @@
// values, use a Sequence to control the matching so the values are returned in a known
// order.
constexpr float kDisplayBrightness = 0.5f;
- Sequence s;
- EXPECT_CALL(*mDisplay, anyLayersRequireClientComposition())
- .InSequence(s)
- .WillOnce(Return(true));
- EXPECT_CALL(*mDisplay, anyLayersRequireClientComposition())
- .InSequence(s)
- .WillOnce(Return(false));
+ constexpr float kDisplayBrightnessNits = 200.f;
EXPECT_CALL(mHwComposer,
- setDisplayBrightness(DEFAULT_DISPLAY_ID, kDisplayBrightness,
+ setDisplayBrightness(DEFAULT_DISPLAY_ID, kDisplayBrightness, kDisplayBrightnessNits,
Hwc2::Composer::DisplayBrightnessOptions{.applyImmediately =
false}))
.WillOnce(Return(ByMove(ftl::yield<status_t>(NO_ERROR))));
- EXPECT_CALL(mHwComposer,
- getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _))
- .WillOnce(Return(NO_ERROR));
- EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false));
-
mDisplay->setNextBrightness(kDisplayBrightness);
- mDisplay->chooseCompositionStrategy();
+ mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
+ EXPECT_CALL(*renderSurface, beginFrame(_)).Times(1);
+ mDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
+ mDisplay->editState().displayBrightnessNits = kDisplayBrightnessNits;
+ mDisplay->beginFrame();
auto& state = mDisplay->getState();
- EXPECT_FALSE(state.usesClientComposition);
- EXPECT_TRUE(state.usesDeviceComposition);
EXPECT_FALSE(state.displayBrightness.has_value());
}
TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) {
- android::HWComposer::DeviceRequestedChanges changes{
- {{nullptr, Composition::CLIENT}},
- hal::DisplayRequest::FLIP_CLIENT_TARGET,
- {{nullptr, hal::LayerRequest::CLEAR_CLIENT_TARGET}},
- {hal::PixelFormat::RGBA_8888, hal::Dataspace::UNKNOWN},
- -1.f,
- };
-
// Since two calls are made to anyLayersRequireClientComposition with different return
// values, use a Sequence to control the matching so the values are returned in a known
// order.
@@ -651,13 +672,15 @@
EXPECT_CALL(mHwComposer,
getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _))
- .WillOnce(DoAll(SetArgPointee<5>(changes), Return(NO_ERROR)));
- EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(changes.changedTypes)).Times(1);
- EXPECT_CALL(*mDisplay, applyDisplayRequests(changes.displayRequests)).Times(1);
- EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(changes.layerRequests)).Times(1);
+ .WillOnce(DoAll(SetArgPointee<5>(mDeviceRequestedChanges), Return(NO_ERROR)));
+ EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(mDeviceRequestedChanges.changedTypes))
+ .Times(1);
+ EXPECT_CALL(*mDisplay, applyDisplayRequests(mDeviceRequestedChanges.displayRequests)).Times(1);
+ EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(mDeviceRequestedChanges.layerRequests))
+ .Times(1);
EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false));
- mDisplay->chooseCompositionStrategy();
+ chooseCompositionStrategy(mDisplay.get());
auto& state = mDisplay->getState();
EXPECT_FALSE(state.usesClientComposition);
@@ -822,23 +845,37 @@
using DisplayApplyClientTargetRequests = DisplayWithLayersTestCommon;
TEST_F(DisplayApplyLayerRequestsToLayersTest, applyClientTargetRequests) {
- Display::ClientTargetProperty clientTargetProperty = {
- .pixelFormat = hal::PixelFormat::RGB_565,
- .dataspace = hal::Dataspace::STANDARD_BT470M,
- };
-
static constexpr float kWhitePointNits = 800.f;
+ Display::ClientTargetProperty clientTargetProperty = {
+ .clientTargetProperty =
+ {
+ .pixelFormat =
+ aidl::android::hardware::graphics::common::PixelFormat::RGB_565,
+ .dataspace = aidl::android::hardware::graphics::common::Dataspace::
+ STANDARD_BT470M,
+ },
+ .brightness = kWhitePointNits,
+ .dimmingStage = aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF,
+ };
+
mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
mDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
- EXPECT_CALL(*renderSurface, setBufferPixelFormat(clientTargetProperty.pixelFormat));
- EXPECT_CALL(*renderSurface, setBufferDataspace(clientTargetProperty.dataspace));
- mDisplay->applyClientTargetRequests(clientTargetProperty, kWhitePointNits);
+ EXPECT_CALL(*renderSurface,
+ setBufferPixelFormat(static_cast<ui::PixelFormat>(
+ clientTargetProperty.clientTargetProperty.pixelFormat)));
+ EXPECT_CALL(*renderSurface,
+ setBufferDataspace(static_cast<ui::Dataspace>(
+ clientTargetProperty.clientTargetProperty.dataspace)));
+ mDisplay->applyClientTargetRequests(clientTargetProperty);
auto& state = mDisplay->getState();
- EXPECT_EQ(clientTargetProperty.dataspace, state.dataspace);
+ EXPECT_EQ(clientTargetProperty.clientTargetProperty.dataspace,
+ static_cast<aidl::android::hardware::graphics::common::Dataspace>(state.dataspace));
EXPECT_EQ(kWhitePointNits, state.clientTargetBrightness);
+ EXPECT_EQ(aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF,
+ state.clientTargetDimmingStage);
}
/*
@@ -921,7 +958,7 @@
mDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1));
mDisplay->editState().dirtyRegion = Region::INVALID_REGION;
- mDisplay->finishFrame({});
+ mDisplay->finishFrame({}, std::move(mResultWithBuffer));
}
TEST_F(DisplayFinishFrameTest, skipsCompositionIfNotDirty) {
@@ -939,7 +976,7 @@
gpuDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1));
gpuDisplay->editState().dirtyRegion = Region::INVALID_REGION;
- gpuDisplay->finishFrame({});
+ gpuDisplay->finishFrame({}, std::move(mResultWithoutBuffer));
}
TEST_F(DisplayFinishFrameTest, performsCompositionIfDirty) {
@@ -956,7 +993,7 @@
gpuDisplay->editState().usesClientComposition = false;
gpuDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1));
gpuDisplay->editState().dirtyRegion = Region(Rect(0, 0, 1, 1));
- gpuDisplay->finishFrame({});
+ gpuDisplay->finishFrame({}, std::move(mResultWithBuffer));
}
/*
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index af013b0..ff2aa15 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -84,8 +84,8 @@
MOCK_METHOD4(setDisplayContentSamplingEnabled, status_t(HalDisplayId, bool, uint8_t, uint64_t));
MOCK_METHOD4(getDisplayedContentSample,
status_t(HalDisplayId, uint64_t, uint64_t, DisplayedFrameStats*));
- MOCK_METHOD3(setDisplayBrightness,
- std::future<status_t>(PhysicalDisplayId, float,
+ MOCK_METHOD4(setDisplayBrightness,
+ std::future<status_t>(PhysicalDisplayId, float, float,
const Hwc2::Composer::DisplayBrightnessOptions&));
MOCK_METHOD2(getDisplayBrightnessSupport, status_t(PhysicalDisplayId, bool*));
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 8eb1946..ceee48c 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -668,6 +668,13 @@
EXPECT_EQ(mOutputState.sdrWhitePointNits / mOutputState.displayBrightnessNits,
mOutputLayer.getState().dimmingRatio);
+ mLayerFEState.dimmingEnabled = false;
+ mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0);
+ EXPECT_EQ(mOutputState.displayBrightnessNits, mOutputLayer.getState().whitePointNits);
+ EXPECT_EQ(1.f, mOutputLayer.getState().dimmingRatio);
+
+ // change dimmingEnabled back to true.
+ mLayerFEState.dimmingEnabled = true;
mLayerFEState.dataspace = ui::Dataspace::BT2020_ITU_PQ;
mLayerFEState.isColorspaceAgnostic = false;
mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0);
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index dd3858b..42c8b37 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -28,6 +28,7 @@
#include <gtest/gtest.h>
#include <renderengine/ExternalTexture.h>
#include <renderengine/impl/ExternalTexture.h>
+#include <renderengine/mock/FakeExternalTexture.h>
#include <renderengine/mock/RenderEngine.h>
#include <ui/Rect.h>
#include <ui/Region.h>
@@ -73,6 +74,9 @@
constexpr OutputColorSetting kVendorSpecifiedOutputColorSetting =
static_cast<OutputColorSetting>(0x100);
+using CompositionStrategyPredictionState = android::compositionengine::impl::
+ OutputCompositionState::CompositionStrategyPredictionState;
+
struct OutputPartialMockBase : public impl::Output {
// compositionengine::Output overrides
const OutputCompositionState& getState() const override { return mState; }
@@ -989,7 +993,9 @@
struct OutputPartialMock : public OutputPartialMockBase {
// Sets up the helper functions called by the function under test to use
// mock implementations.
- MOCK_METHOD0(chooseCompositionStrategy, void());
+ MOCK_METHOD1(chooseCompositionStrategy,
+ bool(std::optional<android::HWComposer::DeviceRequestedChanges>*));
+ MOCK_METHOD0(resetCompositionStrategy, void());
};
OutputPrepareFrameTest() {
@@ -1015,11 +1021,13 @@
mOutput.editState().usesClientComposition = false;
mOutput.editState().usesDeviceComposition = true;
- EXPECT_CALL(mOutput, chooseCompositionStrategy()).Times(1);
+ EXPECT_CALL(mOutput, chooseCompositionStrategy(_)).WillRepeatedly(Return(true));
+ EXPECT_CALL(mOutput, resetCompositionStrategy()).Times(1);
EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u));
EXPECT_CALL(*mRenderSurface, prepareFrame(false, true));
mOutput.prepareFrame();
+ EXPECT_EQ(mOutput.getState().strategyPrediction, CompositionStrategyPredictionState::DISABLED);
}
// Note: Use OutputTest and not OutputPrepareFrameTest, so the real
@@ -1035,6 +1043,148 @@
EXPECT_TRUE(mOutput->getState().usesClientComposition);
EXPECT_FALSE(mOutput->getState().usesDeviceComposition);
+ EXPECT_EQ(mOutput->getState().strategyPrediction, CompositionStrategyPredictionState::DISABLED);
+}
+
+struct OutputPrepareFrameAsyncTest : public testing::Test {
+ struct OutputPartialMock : public OutputPartialMockBase {
+ // Sets up the helper functions called by the function under test to use
+ // mock implementations.
+ MOCK_METHOD1(chooseCompositionStrategy,
+ bool(std::optional<android::HWComposer::DeviceRequestedChanges>*));
+ MOCK_METHOD0(updateProtectedContentState, void());
+ MOCK_METHOD2(dequeueRenderBuffer,
+ bool(base::unique_fd*, std::shared_ptr<renderengine::ExternalTexture>*));
+ MOCK_METHOD1(
+ chooseCompositionStrategyAsync,
+ std::future<bool>(std::optional<android::HWComposer::DeviceRequestedChanges>*));
+ MOCK_METHOD4(composeSurfaces,
+ std::optional<base::unique_fd>(
+ const Region&, const compositionengine::CompositionRefreshArgs&,
+ std::shared_ptr<renderengine::ExternalTexture>, base::unique_fd&));
+ MOCK_METHOD0(resetCompositionStrategy, void());
+ };
+
+ OutputPrepareFrameAsyncTest() {
+ mOutput.setDisplayColorProfileForTest(
+ std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
+ mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
+ }
+
+ StrictMock<mock::CompositionEngine> mCompositionEngine;
+ mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock<mock::DisplayColorProfile>();
+ mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>();
+ StrictMock<OutputPartialMock> mOutput;
+ CompositionRefreshArgs mRefreshArgs;
+};
+
+TEST_F(OutputPrepareFrameAsyncTest, delegatesToChooseCompositionStrategyAndRenderSurface) {
+ mOutput.editState().isEnabled = true;
+ mOutput.editState().usesClientComposition = false;
+ mOutput.editState().usesDeviceComposition = true;
+ mOutput.editState().previousDeviceRequestedChanges =
+ std::make_optional<android::HWComposer::DeviceRequestedChanges>({});
+ std::promise<bool> p;
+ p.set_value(true);
+
+ EXPECT_CALL(mOutput, resetCompositionStrategy()).Times(1);
+ EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u));
+ EXPECT_CALL(mOutput, updateProtectedContentState());
+ EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(true));
+ EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)).Times(1);
+ EXPECT_CALL(mOutput, chooseCompositionStrategyAsync(_))
+ .WillOnce(DoAll(SetArgPointee<0>(mOutput.editState().previousDeviceRequestedChanges),
+ Return(ByMove(p.get_future()))));
+ EXPECT_CALL(mOutput, composeSurfaces(_, Ref(mRefreshArgs), _, _));
+
+ impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs);
+ EXPECT_EQ(mOutput.getState().strategyPrediction, CompositionStrategyPredictionState::SUCCESS);
+ EXPECT_FALSE(result.bufferAvailable());
+}
+
+TEST_F(OutputPrepareFrameAsyncTest, skipCompositionOnDequeueFailure) {
+ mOutput.editState().isEnabled = true;
+ mOutput.editState().usesClientComposition = false;
+ mOutput.editState().usesDeviceComposition = true;
+ mOutput.editState().previousDeviceRequestedChanges =
+ std::make_optional<android::HWComposer::DeviceRequestedChanges>({});
+ std::promise<bool> p;
+ p.set_value(true);
+
+ EXPECT_CALL(mOutput, resetCompositionStrategy()).Times(2);
+ EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u));
+ EXPECT_CALL(mOutput, updateProtectedContentState());
+ EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(false));
+ EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)).Times(2);
+ EXPECT_CALL(mOutput, chooseCompositionStrategyAsync(_))
+ .WillOnce(DoAll(SetArgPointee<0>(mOutput.editState().previousDeviceRequestedChanges),
+ Return(ByMove(p.get_future()))));
+
+ impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs);
+ EXPECT_EQ(mOutput.getState().strategyPrediction, CompositionStrategyPredictionState::FAIL);
+ EXPECT_FALSE(result.bufferAvailable());
+}
+
+// Tests that in the event of hwc error when choosing composition strategy, we would fall back
+// client composition
+TEST_F(OutputPrepareFrameAsyncTest, chooseCompositionStrategyFailureCallsPrepareFrame) {
+ mOutput.editState().isEnabled = true;
+ mOutput.editState().usesClientComposition = false;
+ mOutput.editState().usesDeviceComposition = true;
+ mOutput.editState().previousDeviceRequestedChanges =
+ std::make_optional<android::HWComposer::DeviceRequestedChanges>({});
+ std::promise<bool> p;
+ p.set_value(false);
+ std::shared_ptr<renderengine::ExternalTexture> tex =
+ std::make_shared<renderengine::mock::FakeExternalTexture>(1, 1,
+ HAL_PIXEL_FORMAT_RGBA_8888, 1,
+ 2);
+ EXPECT_CALL(mOutput, resetCompositionStrategy()).Times(2);
+ EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u));
+ EXPECT_CALL(mOutput, updateProtectedContentState());
+ EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _))
+ .WillOnce(DoAll(SetArgPointee<1>(tex), Return(true)));
+ EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)).Times(2);
+ EXPECT_CALL(mOutput, chooseCompositionStrategyAsync(_)).WillOnce([&] {
+ return p.get_future();
+ });
+ EXPECT_CALL(mOutput, composeSurfaces(_, Ref(mRefreshArgs), _, _));
+
+ impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs);
+ EXPECT_EQ(mOutput.getState().strategyPrediction, CompositionStrategyPredictionState::FAIL);
+ EXPECT_TRUE(result.bufferAvailable());
+}
+
+TEST_F(OutputPrepareFrameAsyncTest, predictionMiss) {
+ mOutput.editState().isEnabled = true;
+ mOutput.editState().usesClientComposition = false;
+ mOutput.editState().usesDeviceComposition = true;
+ mOutput.editState().previousDeviceRequestedChanges =
+ std::make_optional<android::HWComposer::DeviceRequestedChanges>({});
+ auto newDeviceRequestedChanges =
+ std::make_optional<android::HWComposer::DeviceRequestedChanges>({});
+ newDeviceRequestedChanges->displayRequests = static_cast<hal::DisplayRequest>(0);
+ std::promise<bool> p;
+ p.set_value(false);
+ std::shared_ptr<renderengine::ExternalTexture> tex =
+ std::make_shared<renderengine::mock::FakeExternalTexture>(1, 1,
+ HAL_PIXEL_FORMAT_RGBA_8888, 1,
+ 2);
+
+ EXPECT_CALL(mOutput, resetCompositionStrategy()).Times(2);
+ EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u));
+ EXPECT_CALL(mOutput, updateProtectedContentState());
+ EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _))
+ .WillOnce(DoAll(SetArgPointee<1>(tex), Return(true)));
+ EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)).Times(2);
+ EXPECT_CALL(mOutput, chooseCompositionStrategyAsync(_)).WillOnce([&] {
+ return p.get_future();
+ });
+ EXPECT_CALL(mOutput, composeSurfaces(_, Ref(mRefreshArgs), _, _));
+
+ impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs);
+ EXPECT_EQ(mOutput.getState().strategyPrediction, CompositionStrategyPredictionState::FAIL);
+ EXPECT_TRUE(result.bufferAvailable());
}
/*
@@ -1820,10 +1970,14 @@
MOCK_METHOD1(setColorTransform, void(const compositionengine::CompositionRefreshArgs&));
MOCK_METHOD0(beginFrame, void());
MOCK_METHOD0(prepareFrame, void());
+ MOCK_METHOD1(prepareFrameAsync, GpuCompositionResult(const CompositionRefreshArgs&));
MOCK_METHOD1(devOptRepaintFlash, void(const compositionengine::CompositionRefreshArgs&));
- MOCK_METHOD1(finishFrame, void(const compositionengine::CompositionRefreshArgs&));
+ MOCK_METHOD2(finishFrame,
+ void(const compositionengine::CompositionRefreshArgs&,
+ GpuCompositionResult&&));
MOCK_METHOD0(postFramebuffer, void());
MOCK_METHOD1(renderCachedSets, void(const compositionengine::CompositionRefreshArgs&));
+ MOCK_METHOD1(canPredictCompositionStrategy, bool(const CompositionRefreshArgs&));
};
StrictMock<OutputPartialMock> mOutput;
@@ -1839,9 +1993,30 @@
EXPECT_CALL(mOutput, writeCompositionState(Ref(args)));
EXPECT_CALL(mOutput, setColorTransform(Ref(args)));
EXPECT_CALL(mOutput, beginFrame());
+ EXPECT_CALL(mOutput, canPredictCompositionStrategy(Ref(args))).WillOnce(Return(false));
EXPECT_CALL(mOutput, prepareFrame());
EXPECT_CALL(mOutput, devOptRepaintFlash(Ref(args)));
- EXPECT_CALL(mOutput, finishFrame(Ref(args)));
+ EXPECT_CALL(mOutput, finishFrame(Ref(args), _));
+ EXPECT_CALL(mOutput, postFramebuffer());
+ EXPECT_CALL(mOutput, renderCachedSets(Ref(args)));
+
+ mOutput.present(args);
+}
+
+TEST_F(OutputPresentTest, predictingCompositionStrategyInvokesPrepareFrameAsync) {
+ CompositionRefreshArgs args;
+
+ InSequence seq;
+ EXPECT_CALL(mOutput, updateColorProfile(Ref(args)));
+ EXPECT_CALL(mOutput, updateCompositionState(Ref(args)));
+ EXPECT_CALL(mOutput, planComposition());
+ EXPECT_CALL(mOutput, writeCompositionState(Ref(args)));
+ EXPECT_CALL(mOutput, setColorTransform(Ref(args)));
+ EXPECT_CALL(mOutput, beginFrame());
+ EXPECT_CALL(mOutput, canPredictCompositionStrategy(Ref(args))).WillOnce(Return(true));
+ EXPECT_CALL(mOutput, prepareFrameAsync(Ref(args)));
+ EXPECT_CALL(mOutput, devOptRepaintFlash(Ref(args)));
+ EXPECT_CALL(mOutput, finishFrame(Ref(args), _));
EXPECT_CALL(mOutput, postFramebuffer());
EXPECT_CALL(mOutput, renderCachedSets(Ref(args)));
@@ -2739,11 +2914,15 @@
// Sets up the helper functions called by the function under test to use
// mock implementations.
MOCK_METHOD(Region, getDirtyRegion, (), (const));
- MOCK_METHOD2(composeSurfaces,
+ MOCK_METHOD4(composeSurfaces,
std::optional<base::unique_fd>(
- const Region&, const compositionengine::CompositionRefreshArgs&));
+ const Region&, const compositionengine::CompositionRefreshArgs&,
+ std::shared_ptr<renderengine::ExternalTexture>, base::unique_fd&));
MOCK_METHOD0(postFramebuffer, void());
MOCK_METHOD0(prepareFrame, void());
+ MOCK_METHOD0(updateProtectedContentState, void());
+ MOCK_METHOD2(dequeueRenderBuffer,
+ bool(base::unique_fd*, std::shared_ptr<renderengine::ExternalTexture>*));
};
OutputDevOptRepaintFlashTest() {
@@ -2800,7 +2979,9 @@
InSequence seq;
EXPECT_CALL(mOutput, getDirtyRegion()).WillOnce(Return(kNotEmptyRegion));
- EXPECT_CALL(mOutput, composeSurfaces(RegionEq(kNotEmptyRegion), Ref(mRefreshArgs)));
+ EXPECT_CALL(mOutput, updateProtectedContentState());
+ EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _));
+ EXPECT_CALL(mOutput, composeSurfaces(RegionEq(kNotEmptyRegion), Ref(mRefreshArgs), _, _));
EXPECT_CALL(*mRenderSurface, queueBuffer(_));
EXPECT_CALL(mOutput, postFramebuffer());
EXPECT_CALL(mOutput, prepareFrame());
@@ -2816,10 +2997,14 @@
struct OutputPartialMock : public OutputPartialMockBase {
// Sets up the helper functions called by the function under test to use
// mock implementations.
- MOCK_METHOD2(composeSurfaces,
+ MOCK_METHOD4(composeSurfaces,
std::optional<base::unique_fd>(
- const Region&, const compositionengine::CompositionRefreshArgs&));
+ const Region&, const compositionengine::CompositionRefreshArgs&,
+ std::shared_ptr<renderengine::ExternalTexture>, base::unique_fd&));
MOCK_METHOD0(postFramebuffer, void());
+ MOCK_METHOD0(updateProtectedContentState, void());
+ MOCK_METHOD2(dequeueRenderBuffer,
+ bool(base::unique_fd*, std::shared_ptr<renderengine::ExternalTexture>*));
};
OutputFinishFrameTest() {
@@ -2837,27 +3022,62 @@
TEST_F(OutputFinishFrameTest, ifNotEnabledDoesNothing) {
mOutput.mState.isEnabled = false;
- mOutput.finishFrame(mRefreshArgs);
+ impl::GpuCompositionResult result;
+ mOutput.finishFrame(mRefreshArgs, std::move(result));
}
TEST_F(OutputFinishFrameTest, takesEarlyOutifComposeSurfacesReturnsNoFence) {
mOutput.mState.isEnabled = true;
+ EXPECT_CALL(mOutput, updateProtectedContentState());
+ EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(true));
+ EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _, _, _));
- InSequence seq;
- EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _));
-
- mOutput.finishFrame(mRefreshArgs);
+ impl::GpuCompositionResult result;
+ mOutput.finishFrame(mRefreshArgs, std::move(result));
}
TEST_F(OutputFinishFrameTest, queuesBufferIfComposeSurfacesReturnsAFence) {
mOutput.mState.isEnabled = true;
InSequence seq;
- EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _))
+ EXPECT_CALL(mOutput, updateProtectedContentState());
+ EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(true));
+ EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _, _, _))
.WillOnce(Return(ByMove(base::unique_fd())));
EXPECT_CALL(*mRenderSurface, queueBuffer(_));
- mOutput.finishFrame(mRefreshArgs);
+ impl::GpuCompositionResult result;
+ mOutput.finishFrame(mRefreshArgs, std::move(result));
+}
+
+TEST_F(OutputFinishFrameTest, predictionSucceeded) {
+ mOutput.mState.isEnabled = true;
+ mOutput.mState.strategyPrediction = CompositionStrategyPredictionState::SUCCESS;
+ InSequence seq;
+ EXPECT_CALL(*mRenderSurface, queueBuffer(_));
+
+ impl::GpuCompositionResult result;
+ mOutput.finishFrame(mRefreshArgs, std::move(result));
+}
+
+TEST_F(OutputFinishFrameTest, predictionFailedAndBufferIsReused) {
+ mOutput.mState.isEnabled = true;
+ mOutput.mState.strategyPrediction = CompositionStrategyPredictionState::FAIL;
+
+ InSequence seq;
+
+ impl::GpuCompositionResult result;
+ result.buffer =
+ std::make_shared<renderengine::mock::FakeExternalTexture>(1, 1,
+ HAL_PIXEL_FORMAT_RGBA_8888, 1,
+ 2);
+
+ EXPECT_CALL(mOutput,
+ composeSurfaces(RegionEq(Region::INVALID_REGION), _, result.buffer,
+ Eq(ByRef(result.fence))))
+ .WillOnce(Return(ByMove(base::unique_fd())));
+ EXPECT_CALL(*mRenderSurface, queueBuffer(_));
+ mOutput.finishFrame(mRefreshArgs, std::move(result));
}
/*
@@ -3104,8 +3324,15 @@
struct ExecuteState : public CallOrderStateMachineHelper<TestType, ExecuteState> {
auto execute() {
- getInstance()->mReadyFence =
- getInstance()->mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
+ base::unique_fd fence;
+ std::shared_ptr<renderengine::ExternalTexture> externalTexture;
+ const bool success =
+ getInstance()->mOutput.dequeueRenderBuffer(&fence, &externalTexture);
+ if (success) {
+ getInstance()->mReadyFence =
+ getInstance()->mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs,
+ externalTexture, fence);
+ }
return nextState<FenceCheckState>();
}
};
@@ -3475,6 +3702,25 @@
: public CallOrderStateMachineHelper<TestType, OutputWithDisplayBrightnessNits> {
auto withDisplayBrightnessNits(float nits) {
getInstance()->mOutput.mState.displayBrightnessNits = nits;
+ return nextState<OutputWithDimmingStage>();
+ }
+ };
+
+ struct OutputWithDimmingStage
+ : public CallOrderStateMachineHelper<TestType, OutputWithDimmingStage> {
+ auto withDimmingStage(
+ aidl::android::hardware::graphics::composer3::DimmingStage dimmingStage) {
+ getInstance()->mOutput.mState.clientTargetDimmingStage = dimmingStage;
+ return nextState<OutputWithRenderIntent>();
+ }
+ };
+
+ struct OutputWithRenderIntent
+ : public CallOrderStateMachineHelper<TestType, OutputWithRenderIntent> {
+ auto withRenderIntent(
+ aidl::android::hardware::graphics::composer3::RenderIntent renderIntent) {
+ getInstance()->mOutput.mState.renderIntent =
+ static_cast<ui::RenderIntent>(renderIntent);
return nextState<SkipColorTransformState>();
}
};
@@ -3507,16 +3753,24 @@
verify().ifMixedCompositionIs(true)
.andIfUsesHdr(true)
.withDisplayBrightnessNits(kUnknownLuminance)
+ .withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
+ .withRenderIntent(
+ aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
.andIfSkipColorTransform(false)
- .thenExpectDisplaySettingsUsed({.physicalDisplay = kDefaultOutputDestinationClip,
- .clip = kDefaultOutputViewport,
- .maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
- .outputDataspace = kDefaultOutputDataspace,
- .colorTransform = kDefaultColorTransformMat,
- .deviceHandlesColorTransform = true,
- .orientation = kDefaultOutputOrientationFlags,
- .targetLuminanceNits = kClientTargetLuminanceNits})
+ .thenExpectDisplaySettingsUsed(
+ {.physicalDisplay = kDefaultOutputDestinationClip,
+ .clip = kDefaultOutputViewport,
+ .maxLuminance = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDefaultMaxLuminance,
+ .outputDataspace = kDefaultOutputDataspace,
+ .colorTransform = kDefaultColorTransformMat,
+ .deviceHandlesColorTransform = true,
+ .orientation = kDefaultOutputOrientationFlags,
+ .targetLuminanceNits = kClientTargetLuminanceNits,
+ .dimmingStage =
+ aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR,
+ .renderIntent = aidl::android::hardware::graphics::composer3::RenderIntent::
+ COLORIMETRIC})
.execute()
.expectAFenceWasReturned();
}
@@ -3526,16 +3780,78 @@
verify().ifMixedCompositionIs(true)
.andIfUsesHdr(true)
.withDisplayBrightnessNits(kDisplayLuminance)
+ .withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
+ .withRenderIntent(
+ aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
.andIfSkipColorTransform(false)
- .thenExpectDisplaySettingsUsed({.physicalDisplay = kDefaultOutputDestinationClip,
- .clip = kDefaultOutputViewport,
- .maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDisplayLuminance,
- .outputDataspace = kDefaultOutputDataspace,
- .colorTransform = kDefaultColorTransformMat,
- .deviceHandlesColorTransform = true,
- .orientation = kDefaultOutputOrientationFlags,
- .targetLuminanceNits = kClientTargetLuminanceNits})
+ .thenExpectDisplaySettingsUsed(
+ {.physicalDisplay = kDefaultOutputDestinationClip,
+ .clip = kDefaultOutputViewport,
+ .maxLuminance = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDisplayLuminance,
+ .outputDataspace = kDefaultOutputDataspace,
+ .colorTransform = kDefaultColorTransformMat,
+ .deviceHandlesColorTransform = true,
+ .orientation = kDefaultOutputOrientationFlags,
+ .targetLuminanceNits = kClientTargetLuminanceNits,
+ .dimmingStage =
+ aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR,
+ .renderIntent = aidl::android::hardware::graphics::composer3::RenderIntent::
+ COLORIMETRIC})
+ .execute()
+ .expectAFenceWasReturned();
+}
+
+TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings,
+ forHdrMixedCompositionWithDimmingStage) {
+ verify().ifMixedCompositionIs(true)
+ .andIfUsesHdr(true)
+ .withDisplayBrightnessNits(kUnknownLuminance)
+ .withDimmingStage(
+ aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF)
+ .withRenderIntent(
+ aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
+ .andIfSkipColorTransform(false)
+ .thenExpectDisplaySettingsUsed(
+ {.physicalDisplay = kDefaultOutputDestinationClip,
+ .clip = kDefaultOutputViewport,
+ .maxLuminance = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDefaultMaxLuminance,
+ .outputDataspace = kDefaultOutputDataspace,
+ .colorTransform = kDefaultColorTransformMat,
+ .deviceHandlesColorTransform = true,
+ .orientation = kDefaultOutputOrientationFlags,
+ .targetLuminanceNits = kClientTargetLuminanceNits,
+ .dimmingStage =
+ aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF,
+ .renderIntent = aidl::android::hardware::graphics::composer3::RenderIntent::
+ COLORIMETRIC})
+ .execute()
+ .expectAFenceWasReturned();
+}
+
+TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings,
+ forHdrMixedCompositionWithRenderIntent) {
+ verify().ifMixedCompositionIs(true)
+ .andIfUsesHdr(true)
+ .withDisplayBrightnessNits(kUnknownLuminance)
+ .withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
+ .withRenderIntent(aidl::android::hardware::graphics::composer3::RenderIntent::ENHANCE)
+ .andIfSkipColorTransform(false)
+ .thenExpectDisplaySettingsUsed(
+ {.physicalDisplay = kDefaultOutputDestinationClip,
+ .clip = kDefaultOutputViewport,
+ .maxLuminance = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDefaultMaxLuminance,
+ .outputDataspace = kDefaultOutputDataspace,
+ .colorTransform = kDefaultColorTransformMat,
+ .deviceHandlesColorTransform = true,
+ .orientation = kDefaultOutputOrientationFlags,
+ .targetLuminanceNits = kClientTargetLuminanceNits,
+ .dimmingStage =
+ aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR,
+ .renderIntent =
+ aidl::android::hardware::graphics::composer3::RenderIntent::ENHANCE})
.execute()
.expectAFenceWasReturned();
}
@@ -3544,16 +3860,24 @@
verify().ifMixedCompositionIs(true)
.andIfUsesHdr(false)
.withDisplayBrightnessNits(kUnknownLuminance)
+ .withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
+ .withRenderIntent(
+ aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
.andIfSkipColorTransform(false)
- .thenExpectDisplaySettingsUsed({.physicalDisplay = kDefaultOutputDestinationClip,
- .clip = kDefaultOutputViewport,
- .maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
- .outputDataspace = kDefaultOutputDataspace,
- .colorTransform = kDefaultColorTransformMat,
- .deviceHandlesColorTransform = true,
- .orientation = kDefaultOutputOrientationFlags,
- .targetLuminanceNits = kClientTargetLuminanceNits})
+ .thenExpectDisplaySettingsUsed(
+ {.physicalDisplay = kDefaultOutputDestinationClip,
+ .clip = kDefaultOutputViewport,
+ .maxLuminance = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDefaultMaxLuminance,
+ .outputDataspace = kDefaultOutputDataspace,
+ .colorTransform = kDefaultColorTransformMat,
+ .deviceHandlesColorTransform = true,
+ .orientation = kDefaultOutputOrientationFlags,
+ .targetLuminanceNits = kClientTargetLuminanceNits,
+ .dimmingStage =
+ aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR,
+ .renderIntent = aidl::android::hardware::graphics::composer3::RenderIntent::
+ COLORIMETRIC})
.execute()
.expectAFenceWasReturned();
}
@@ -3562,16 +3886,24 @@
verify().ifMixedCompositionIs(false)
.andIfUsesHdr(true)
.withDisplayBrightnessNits(kUnknownLuminance)
+ .withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
+ .withRenderIntent(
+ aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
.andIfSkipColorTransform(false)
- .thenExpectDisplaySettingsUsed({.physicalDisplay = kDefaultOutputDestinationClip,
- .clip = kDefaultOutputViewport,
- .maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
- .outputDataspace = kDefaultOutputDataspace,
- .colorTransform = kDefaultColorTransformMat,
- .deviceHandlesColorTransform = false,
- .orientation = kDefaultOutputOrientationFlags,
- .targetLuminanceNits = kClientTargetLuminanceNits})
+ .thenExpectDisplaySettingsUsed(
+ {.physicalDisplay = kDefaultOutputDestinationClip,
+ .clip = kDefaultOutputViewport,
+ .maxLuminance = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDefaultMaxLuminance,
+ .outputDataspace = kDefaultOutputDataspace,
+ .colorTransform = kDefaultColorTransformMat,
+ .deviceHandlesColorTransform = false,
+ .orientation = kDefaultOutputOrientationFlags,
+ .targetLuminanceNits = kClientTargetLuminanceNits,
+ .dimmingStage =
+ aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR,
+ .renderIntent = aidl::android::hardware::graphics::composer3::RenderIntent::
+ COLORIMETRIC})
.execute()
.expectAFenceWasReturned();
}
@@ -3580,16 +3912,24 @@
verify().ifMixedCompositionIs(false)
.andIfUsesHdr(false)
.withDisplayBrightnessNits(kUnknownLuminance)
+ .withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
+ .withRenderIntent(
+ aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
.andIfSkipColorTransform(false)
- .thenExpectDisplaySettingsUsed({.physicalDisplay = kDefaultOutputDestinationClip,
- .clip = kDefaultOutputViewport,
- .maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
- .outputDataspace = kDefaultOutputDataspace,
- .colorTransform = kDefaultColorTransformMat,
- .deviceHandlesColorTransform = false,
- .orientation = kDefaultOutputOrientationFlags,
- .targetLuminanceNits = kClientTargetLuminanceNits})
+ .thenExpectDisplaySettingsUsed(
+ {.physicalDisplay = kDefaultOutputDestinationClip,
+ .clip = kDefaultOutputViewport,
+ .maxLuminance = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDefaultMaxLuminance,
+ .outputDataspace = kDefaultOutputDataspace,
+ .colorTransform = kDefaultColorTransformMat,
+ .deviceHandlesColorTransform = false,
+ .orientation = kDefaultOutputOrientationFlags,
+ .targetLuminanceNits = kClientTargetLuminanceNits,
+ .dimmingStage =
+ aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR,
+ .renderIntent = aidl::android::hardware::graphics::composer3::RenderIntent::
+ COLORIMETRIC})
.execute()
.expectAFenceWasReturned();
}
@@ -3599,16 +3939,24 @@
verify().ifMixedCompositionIs(false)
.andIfUsesHdr(true)
.withDisplayBrightnessNits(kUnknownLuminance)
+ .withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
+ .withRenderIntent(
+ aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
.andIfSkipColorTransform(true)
- .thenExpectDisplaySettingsUsed({.physicalDisplay = kDefaultOutputDestinationClip,
- .clip = kDefaultOutputViewport,
- .maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
- .outputDataspace = kDefaultOutputDataspace,
- .colorTransform = kDefaultColorTransformMat,
- .deviceHandlesColorTransform = true,
- .orientation = kDefaultOutputOrientationFlags,
- .targetLuminanceNits = kClientTargetLuminanceNits})
+ .thenExpectDisplaySettingsUsed(
+ {.physicalDisplay = kDefaultOutputDestinationClip,
+ .clip = kDefaultOutputViewport,
+ .maxLuminance = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDefaultMaxLuminance,
+ .outputDataspace = kDefaultOutputDataspace,
+ .colorTransform = kDefaultColorTransformMat,
+ .deviceHandlesColorTransform = true,
+ .orientation = kDefaultOutputOrientationFlags,
+ .targetLuminanceNits = kClientTargetLuminanceNits,
+ .dimmingStage =
+ aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR,
+ .renderIntent = aidl::android::hardware::graphics::composer3::RenderIntent::
+ COLORIMETRIC})
.execute()
.expectAFenceWasReturned();
}
@@ -3666,7 +4014,11 @@
EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(true));
EXPECT_CALL(mRenderEngine, useProtectedContext(false));
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifRenderEngineDoesNotSupportIt) {
@@ -3674,7 +4026,11 @@
mLayer2.mLayerFEState.hasProtectedContent = true;
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNoProtectedContentLayers) {
@@ -3686,7 +4042,11 @@
EXPECT_CALL(mRenderEngine, useProtectedContext(false));
EXPECT_CALL(*mRenderSurface, setProtected(false));
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNotEnabled) {
@@ -3708,7 +4068,11 @@
.WillOnce(Return(ByMove(
futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledEverywhere) {
@@ -3718,7 +4082,11 @@
EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(true));
EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(true));
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifFailsToEnableInRenderEngine) {
@@ -3729,7 +4097,11 @@
EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(false));
EXPECT_CALL(mRenderEngine, useProtectedContext(true));
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledInRenderEngine) {
@@ -3740,7 +4112,11 @@
EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(false));
EXPECT_CALL(*mRenderSurface, setProtected(true));
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledInRenderSurface) {
@@ -3751,7 +4127,11 @@
EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(true));
EXPECT_CALL(mRenderEngine, useProtectedContext(true));
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
}
struct OutputComposeSurfacesTest_SetsExpensiveRendering : public OutputComposeSurfacesTest {
@@ -3781,7 +4161,11 @@
.WillOnce(Return(ByMove(
futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
}
struct OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur
@@ -3816,7 +4200,12 @@
mOutput.writeCompositionState(mRefreshArgs);
EXPECT_CALL(mOutput, setExpensiveRenderingExpected(true));
- mOutput.composeSurfaces(kDebugRegion, mRefreshArgs);
+
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, mRefreshArgs, tex, fd);
}
TEST_F(OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur, IfBlursAreNotExpensive) {
@@ -3826,7 +4215,12 @@
mOutput.writeCompositionState(mRefreshArgs);
EXPECT_CALL(mOutput, setExpensiveRenderingExpected(true)).Times(0);
- mOutput.composeSurfaces(kDebugRegion, mRefreshArgs);
+
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, mRefreshArgs, tex, fd);
}
/*
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
index bd4ff13..5c6e8da 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
@@ -97,12 +97,12 @@
void verifyUniqueDifferingFields(const LayerState& lhs, const LayerState& rhs) {
EXPECT_EQ(lhs.getHash(), rhs.getHash());
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None), lhs.getDifferingFields(rhs));
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None), rhs.getDifferingFields(lhs));
+ EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::None), lhs.getDifferingFields(rhs));
+ EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::None), rhs.getDifferingFields(lhs));
}
void verifyNonUniqueDifferingFields(const LayerState& lhs, const LayerState& rhs,
- Flags<LayerStateField> fields) {
+ ftl::Flags<LayerStateField> fields) {
EXPECT_NE(lhs.getHash(), rhs.getHash());
EXPECT_EQ(fields, lhs.getDifferingFields(rhs));
@@ -159,9 +159,9 @@
sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionState, sSequenceIdTwo);
- Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+ ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
EXPECT_EQ(sSequenceIdTwo, mLayerState->getId());
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Id), updates);
+ EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::Id), updates);
}
TEST_F(LayerStateTest, compareId) {
@@ -204,9 +204,9 @@
sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionState, sSequenceId, sDebugNameTwo);
- Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+ ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
EXPECT_EQ(sDebugNameTwo, mLayerState->getName());
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Name), updates);
+ EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::Name), updates);
}
TEST_F(LayerStateTest, compareName) {
@@ -253,9 +253,9 @@
outputLayerCompositionStateTwo.displayFrame = sRectTwo;
setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo,
layerFECompositionState);
- Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+ ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
EXPECT_EQ(sRectTwo, mLayerState->getDisplayFrame());
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::DisplayFrame), updates);
+ EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::DisplayFrame), updates);
}
TEST_F(LayerStateTest, compareDisplayFrame) {
@@ -315,9 +315,9 @@
layerFECompositionStateTwo.compositionType = Composition::SOLID_COLOR;
setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
- Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+ ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
EXPECT_EQ(Composition::SOLID_COLOR, mLayerState->getCompositionType());
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::CompositionType), updates);
+ EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::CompositionType), updates);
}
TEST_F(LayerStateTest, compareCompositionType) {
@@ -357,8 +357,8 @@
layerFECompositionStateTwo.buffer = new GraphicBuffer();
setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
- Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Buffer), updates);
+ ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+ EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::Buffer), updates);
}
TEST_F(LayerStateTest, updateBufferSingleBufferedLegacy) {
@@ -380,8 +380,8 @@
layerFECompositionStateTwo.frameNumber = i;
setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
- Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Buffer), updates);
+ ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+ EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::Buffer), updates);
}
}
@@ -404,8 +404,8 @@
for (uint64_t i = 0; i < 10; i++) {
setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
- Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Buffer), updates);
+ ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+ EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::Buffer), updates);
}
}
@@ -446,8 +446,8 @@
outputLayerCompositionStateTwo.sourceCrop = sFloatRectTwo;
setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo,
layerFECompositionState);
- Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SourceCrop), updates);
+ ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+ EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::SourceCrop), updates);
}
TEST_F(LayerStateTest, compareSourceCrop) {
@@ -485,8 +485,8 @@
outputLayerCompositionStateTwo.bufferTransform = Hwc2::Transform::FLIP_V;
setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo,
layerFECompositionState);
- Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::BufferTransform), updates);
+ ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+ EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::BufferTransform), updates);
}
TEST_F(LayerStateTest, compareBufferTransform) {
@@ -525,8 +525,8 @@
layerFECompositionStateTwo.blendMode = hal::BlendMode::PREMULTIPLIED;
setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
- Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::BlendMode), updates);
+ ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+ EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::BlendMode), updates);
}
TEST_F(LayerStateTest, compareBlendMode) {
@@ -564,8 +564,8 @@
layerFECompositionStateTwo.alpha = sAlphaTwo;
setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
- Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Alpha), updates);
+ ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+ EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::Alpha), updates);
}
TEST_F(LayerStateTest, compareAlpha) {
@@ -603,8 +603,8 @@
layerFECompositionStateTwo.metadata[sMetadataKeyTwo] = sMetadataValueTwo;
setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
- Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::LayerMetadata), updates);
+ ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+ EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::LayerMetadata), updates);
}
TEST_F(LayerStateTest, compareLayerMetadata) {
@@ -652,8 +652,8 @@
outputLayerCompositionStateTwo.visibleRegion = sRegionTwo;
setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo,
layerFECompositionState);
- Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::VisibleRegion), updates);
+ ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+ EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::VisibleRegion), updates);
}
TEST_F(LayerStateTest, compareVisibleRegion) {
@@ -691,8 +691,8 @@
outputLayerCompositionStateTwo.dataspace = ui::Dataspace::DISPLAY_P3;
setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo,
layerFECompositionState);
- Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Dataspace), updates);
+ ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+ EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::Dataspace), updates);
}
TEST_F(LayerStateTest, compareDataspace) {
@@ -738,9 +738,9 @@
"buffer2");
setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
- Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Buffer) |
- Flags<LayerStateField>(LayerStateField::PixelFormat),
+ ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+ EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::Buffer) |
+ ftl::Flags<LayerStateField>(LayerStateField::PixelFormat),
updates);
}
@@ -768,7 +768,7 @@
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState,
- Flags<LayerStateField>(LayerStateField::PixelFormat));
+ ftl::Flags<LayerStateField>(LayerStateField::PixelFormat));
EXPECT_TRUE(mLayerState->compare(*otherLayerState));
EXPECT_TRUE(otherLayerState->compare(*mLayerState));
@@ -790,8 +790,8 @@
layerFECompositionStateTwo.colorTransform = sMat4One;
setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
- Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::ColorTransform), updates);
+ ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+ EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::ColorTransform), updates);
}
TEST_F(LayerStateTest, compareColorTransform) {
@@ -831,8 +831,8 @@
layerFECompositionStateTwo.sidebandStream = NativeHandle::create(sFakeSidebandStreamTwo, false);
setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
- Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SidebandStream), updates);
+ ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+ EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::SidebandStream), updates);
}
TEST_F(LayerStateTest, compareSidebandStream) {
@@ -870,8 +870,8 @@
layerFECompositionStateTwo.color = sHalf4Two;
setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
- Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SolidColor), updates);
+ ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+ EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::SolidColor), updates);
}
TEST_F(LayerStateTest, compareSolidColor) {
@@ -909,8 +909,8 @@
layerFECompositionStateTwo.backgroundBlurRadius = sBgBlurRadiusTwo;
setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
- Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::BackgroundBlurRadius), updates);
+ ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+ EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::BackgroundBlurRadius), updates);
}
TEST_F(LayerStateTest, compareBackgroundBlur) {
@@ -949,8 +949,8 @@
layerFECompositionStateTwo.blurRegions.push_back(sBlurRegionTwo);
setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
- Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::BlurRegions), updates);
+ ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+ EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::BlurRegions), updates);
}
TEST_F(LayerStateTest, compareBlurRegions) {
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index f5a4b3d..52529d6 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -24,7 +24,6 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <android-base/stringprintf.h>
#include <compositionengine/CompositionEngine.h>
#include <compositionengine/Display.h>
#include <compositionengine/DisplayColorProfile.h>
@@ -49,8 +48,6 @@
namespace hal = hardware::graphics::composer::hal;
-using android::base::StringAppendF;
-
ui::Transform::RotationFlags DisplayDevice::sPrimaryDisplayRotationFlags = ui::Transform::ROT_0;
DisplayDeviceCreationArgs::DisplayDeviceCreationArgs(
@@ -91,6 +88,7 @@
static_cast<uint32_t>(SurfaceFlinger::maxFrameBufferAcquiredBuffers));
}
+ mCompositionDisplay->setPredictCompositionStrategy(mFlinger->mPredictCompositionStrategy);
mCompositionDisplay->createDisplayColorProfile(
compositionengine::DisplayColorProfileCreationArgsBuilder()
.setHasWideColorGamut(args.hasWideColorGamut)
@@ -298,26 +296,24 @@
sPrimaryDisplayRotationFlags = ui::Transform::toRotationFlags(orientation);
}
- if (!orientedDisplaySpaceRect.isValid()) {
- // The destination frame can be invalid if it has never been set,
- // in that case we assume the whole display size.
- orientedDisplaySpaceRect =
- getCompositionDisplay()->getState().displaySpace.getBoundsAsRect();
- }
-
- if (layerStackSpaceRect.isEmpty()) {
- // The layerStackSpaceRect can be invalid if it has never been set, in that case
- // we assume the whole framebuffer size.
- layerStackSpaceRect =
- getCompositionDisplay()->getState().framebufferSpace.getBoundsAsRect();
- if (orientation == ui::ROTATION_90 || orientation == ui::ROTATION_270) {
- std::swap(layerStackSpaceRect.right, layerStackSpaceRect.bottom);
- }
- }
-
// We need to take care of display rotation for globalTransform for case if the panel is not
// installed aligned with device orientation.
const auto transformOrientation = orientation + mPhysicalOrientation;
+
+ const auto& state = getCompositionDisplay()->getState();
+
+ // If the layer stack and destination frames have never been set, then configure them to be the
+ // same as the physical device, taking into account the total transform.
+ if (!orientedDisplaySpaceRect.isValid()) {
+ ui::Size bounds = state.displaySpace.getBounds();
+ bounds.rotate(transformOrientation);
+ orientedDisplaySpaceRect = Rect(bounds);
+ }
+ if (layerStackSpaceRect.isEmpty()) {
+ ui::Size bounds = state.framebufferSpace.getBounds();
+ bounds.rotate(transformOrientation);
+ layerStackSpaceRect = Rect(bounds);
+ }
getCompositionDisplay()->setProjection(transformOrientation, layerStackSpaceRect,
orientedDisplaySpaceRect);
}
@@ -343,38 +339,40 @@
}
std::string DisplayDevice::getDebugName() const {
- const char* type = "virtual";
+ using namespace std::string_literals;
+
+ std::string name = "Display "s + to_string(getId()) + " ("s;
+
if (mConnectionType) {
- type = isInternal() ? "internal" : "external";
+ name += isInternal() ? "internal"s : "external"s;
+ } else {
+ name += "virtual"s;
}
- return base::StringPrintf("DisplayDevice{%s, %s%s, \"%s\"}", to_string(getId()).c_str(), type,
- isPrimary() ? ", primary" : "", mDisplayName.c_str());
+ if (isPrimary()) {
+ name += ", primary"s;
+ }
+
+ return name + ", \""s + mDisplayName + "\")"s;
}
void DisplayDevice::dump(std::string& result) const {
- StringAppendF(&result, "+ %s\n", getDebugName().c_str());
- StringAppendF(&result, " powerMode=%s (%d)\n", to_string(mPowerMode).c_str(),
- static_cast<int32_t>(mPowerMode));
- const auto activeMode = getActiveMode();
- StringAppendF(&result, " activeMode=%s\n",
- activeMode ? to_string(*activeMode).c_str() : "none");
+ using namespace std::string_literals;
- result.append(" supportedModes=\n");
- for (const auto& [id, mode] : mSupportedModes) {
- result.append(" ");
- result.append(to_string(*mode));
- result.push_back('\n');
+ result += getDebugName();
+
+ if (!isVirtual()) {
+ result += "\n deviceProductInfo="s;
+ if (mDeviceProductInfo) {
+ mDeviceProductInfo->dump(result);
+ } else {
+ result += "{}"s;
+ }
}
- StringAppendF(&result, " deviceProductInfo=");
- if (mDeviceProductInfo) {
- mDeviceProductInfo->dump(result);
- } else {
- result.append("{}");
- }
- result.append("\n");
- getCompositionDisplay()->dump(result);
+ result += "\n powerMode="s;
+ result += to_string(mPowerMode);
+ result += '\n';
if (mRefreshRateConfigs) {
mRefreshRateConfigs->dump(result);
@@ -471,9 +469,8 @@
return;
}
- const auto [lowFps, highFps] = mRefreshRateConfigs->getSupportedRefreshRateRange();
- mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(*mFlinger, lowFps.getIntValue(),
- highFps.getIntValue(), showSpinnner);
+ const auto fpsRange = mRefreshRateConfigs->getSupportedRefreshRateRange();
+ mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(fpsRange, showSpinnner);
mRefreshRateOverlay->setLayerStack(getLayerStack());
mRefreshRateOverlay->setViewport(getSize());
mRefreshRateOverlay->changeRefreshRate(getActiveMode()->getFps());
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 2c4a300..d5d87b4 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -21,6 +21,7 @@
#include <string>
#include <unordered_map>
+#include <android-base/thread_annotations.h>
#include <android/native_window.h>
#include <binder/IBinder.h>
#include <gui/LayerState.h>
@@ -28,6 +29,7 @@
#include <renderengine/RenderEngine.h>
#include <system/window.h>
#include <ui/DisplayId.h>
+#include <ui/DisplayIdentification.h>
#include <ui/DisplayState.h>
#include <ui/GraphicTypes.h>
#include <ui/HdrCapabilities.h>
@@ -39,15 +41,11 @@
#include <utils/RefBase.h>
#include <utils/Timers.h>
-#include "MainThreadGuard.h"
-
-#include <ui/DisplayIdentification.h>
#include "DisplayHardware/DisplayMode.h"
#include "DisplayHardware/Hal.h"
#include "DisplayHardware/PowerAdvisor.h"
-
#include "Scheduler/RefreshRateConfigs.h"
-
+#include "ThreadContext.h"
#include "TracedOrdinal.h"
namespace android {
@@ -99,9 +97,9 @@
void setLayerStack(ui::LayerStack);
void setDisplaySize(int width, int height);
void setProjection(ui::Rotation orientation, Rect viewport, Rect frame);
- void stageBrightness(float brightness) REQUIRES(SF_MAIN_THREAD);
- void persistBrightness(bool needsComposite) REQUIRES(SF_MAIN_THREAD);
- bool isBrightnessStale() const REQUIRES(SF_MAIN_THREAD);
+ void stageBrightness(float brightness) REQUIRES(kMainThreadContext);
+ void persistBrightness(bool needsComposite) REQUIRES(kMainThreadContext);
+ bool isBrightnessStale() const REQUIRES(kMainThreadContext);
void setFlags(uint32_t flags);
ui::Rotation getPhysicalOrientation() const { return mPhysicalOrientation; }
@@ -109,7 +107,7 @@
static ui::Transform::RotationFlags getPrimaryDisplayRotationFlags();
- std::optional<float> getStagedBrightness() const REQUIRES(SF_MAIN_THREAD);
+ std::optional<float> getStagedBrightness() const REQUIRES(kMainThreadContext);
ui::Transform::RotationFlags getTransformHint() const;
const ui::Transform& getTransform() const;
const Rect& getLayerStackSpaceRect() const;
@@ -209,15 +207,15 @@
bool setDesiredActiveMode(const ActiveModeInfo&) EXCLUDES(mActiveModeLock);
std::optional<ActiveModeInfo> getDesiredActiveMode() const EXCLUDES(mActiveModeLock);
void clearDesiredActiveModeState() EXCLUDES(mActiveModeLock);
- ActiveModeInfo getUpcomingActiveMode() const REQUIRES(SF_MAIN_THREAD) {
+ ActiveModeInfo getUpcomingActiveMode() const REQUIRES(kMainThreadContext) {
return mUpcomingActiveMode;
}
- void setActiveMode(DisplayModeId) REQUIRES(SF_MAIN_THREAD);
+ void setActiveMode(DisplayModeId) REQUIRES(kMainThreadContext);
status_t initiateModeChange(const ActiveModeInfo&,
const hal::VsyncPeriodChangeConstraints& constraints,
hal::VsyncPeriodChangeTimeline* outTimeline)
- REQUIRES(SF_MAIN_THREAD);
+ REQUIRES(kMainThreadContext);
// Return the immutable list of supported display modes. The HWC may report different modes
// after a hotplug reconnect event, in which case the DisplayDevice object will be recreated.
@@ -304,7 +302,7 @@
ActiveModeInfo mDesiredActiveMode GUARDED_BY(mActiveModeLock);
TracedOrdinal<bool> mDesiredActiveModeChanged
GUARDED_BY(mActiveModeLock) = {"DesiredActiveModeChanged", false};
- ActiveModeInfo mUpcomingActiveMode GUARDED_BY(SF_MAIN_THREAD);
+ ActiveModeInfo mUpcomingActiveMode GUARDED_BY(kMainThreadContext);
};
struct DisplayDeviceState {
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index 297a776..79dcd15 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -41,6 +41,7 @@
using aidl::android::hardware::graphics::composer3::BnComposerCallback;
using aidl::android::hardware::graphics::composer3::Capability;
+using aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness;
using aidl::android::hardware::graphics::composer3::PowerMode;
using aidl::android::hardware::graphics::composer3::VirtualDisplay;
@@ -155,15 +156,6 @@
.refreshTimeNanos = x.refreshTimeNanos,
};
}
-
-template <>
-IComposerClient::ClientTargetProperty translate(ClientTargetProperty x) {
- return IComposerClient::ClientTargetProperty{
- .pixelFormat = translate<PixelFormat>(x.pixelFormat),
- .dataspace = translate<Dataspace>(x.dataspace),
- };
-}
-
mat4 makeMat4(std::vector<float> in) {
return mat4(static_cast<const float*>(in.data()));
}
@@ -935,9 +927,9 @@
return Error::NONE;
}
-Error AidlComposer::setDisplayBrightness(Display display, float brightness,
+Error AidlComposer::setDisplayBrightness(Display display, float brightness, float brightnessNits,
const DisplayBrightnessOptions& options) {
- mWriter.setDisplayBrightness(translate<int64_t>(display), brightness);
+ mWriter.setDisplayBrightness(translate<int64_t>(display), brightness, brightnessNits);
if (options.applyImmediately) {
return execute();
@@ -1082,12 +1074,8 @@
}
Error AidlComposer::getClientTargetProperty(
- Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty,
- float* outBrightness) {
- const auto property = mReader.takeClientTargetProperty(translate<int64_t>(display));
- *outClientTargetProperty =
- translate<IComposerClient::ClientTargetProperty>(property.clientTargetProperty);
- *outBrightness = property.brightness;
+ Display display, ClientTargetPropertyWithBrightness* outClientTargetProperty) {
+ *outClientTargetProperty = mReader.takeClientTargetProperty(translate<int64_t>(display));
return Error::NONE;
}
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
index 28ff167..18d2242 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
@@ -183,7 +183,7 @@
Error setLayerPerFrameMetadataBlobs(
Display display, Layer layer,
const std::vector<IComposerClient::PerFrameMetadataBlob>& metadata) override;
- Error setDisplayBrightness(Display display, float brightness,
+ Error setDisplayBrightness(Display display, float brightness, float brightnessNits,
const DisplayBrightnessOptions& options) override;
// Composer HAL 2.4
@@ -208,9 +208,10 @@
bool mandatory, const std::vector<uint8_t>& value) override;
V2_4::Error getLayerGenericMetadataKeys(
std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) override;
- Error getClientTargetProperty(Display display,
- IComposerClient::ClientTargetProperty* outClientTargetProperty,
- float* outBrightness) override;
+ Error getClientTargetProperty(
+ Display display,
+ aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness*
+ outClientTargetProperty) override;
// AIDL Composer HAL
Error setLayerBrightness(Display display, Layer layer, float brightness) override;
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 2dc0830..d266d94 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -33,6 +33,7 @@
#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
#include <aidl/android/hardware/graphics/composer3/Capability.h>
+#include <aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.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>
@@ -236,7 +237,7 @@
return applyImmediately == other.applyImmediately;
}
};
- virtual Error setDisplayBrightness(Display display, float brightness,
+ virtual Error setDisplayBrightness(Display display, float brightness, float brightnessNits,
const DisplayBrightnessOptions& options) = 0;
// Composer HAL 2.4
@@ -264,8 +265,7 @@
std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) = 0;
virtual Error getClientTargetProperty(
- Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty,
- float* outBrightness) = 0;
+ Display display, V3_0::ClientTargetPropertyWithBrightness* outClientTargetProperty) = 0;
// AIDL Composer
virtual Error setLayerBrightness(Display display, Layer layer, float brightness) = 0;
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 8d685cf..eb14933 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -44,18 +44,10 @@
#include "HWComposer.h"
#include "../SurfaceFlinger.h"
-// ----------------------------------------------------------------------------
namespace android {
-// ----------------------------------------------------------------------------
using ui::Dataspace;
-/*
- * This implements the (main) framebuffer management. This class is used
- * mostly by SurfaceFlinger, but also by command line GL application.
- *
- */
-
FramebufferSurface::FramebufferSurface(HWComposer& hwc, PhysicalDisplayId displayId,
const sp<IGraphicBufferConsumer>& consumer,
const ui::Size& size, const ui::Size& maxSize)
@@ -205,14 +197,14 @@
void FramebufferSurface::dumpAsString(String8& result) const {
Mutex::Autolock lock(mMutex);
- result.appendFormat(" FramebufferSurface: dataspace: %s(%d)\n",
+ result.append(" FramebufferSurface\n");
+ result.appendFormat(" mDataSpace=%s (%d)\n",
dataspaceDetails(static_cast<android_dataspace>(mDataSpace)).c_str(),
mDataSpace);
- ConsumerBase::dumpLocked(result, " ");
+ ConsumerBase::dumpLocked(result, " ");
}
-void FramebufferSurface::dumpLocked(String8& result, const char* prefix) const
-{
+void FramebufferSurface::dumpLocked(String8& result, const char* prefix) const {
ConsumerBase::dumpLocked(result, prefix);
}
@@ -220,9 +212,7 @@
return mCurrentFence;
}
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
+} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index c0432bf..adf4be3 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -544,9 +544,11 @@
}
std::future<Error> Display::setDisplayBrightness(
- float brightness, const Hwc2::Composer::DisplayBrightnessOptions& options) {
- return ftl::defer([composer = &mComposer, id = mId, brightness, options] {
- const auto intError = composer->setDisplayBrightness(id, brightness, options);
+ float brightness, float brightnessNits,
+ const Hwc2::Composer::DisplayBrightnessOptions& options) {
+ return ftl::defer([composer = &mComposer, id = mId, brightness, brightnessNits, options] {
+ const auto intError =
+ composer->setDisplayBrightness(id, brightness, brightnessNits, options);
return static_cast<Error>(intError);
});
}
@@ -585,10 +587,10 @@
return static_cast<Error>(intError);
}
-Error Display::getClientTargetProperty(ClientTargetProperty* outClientTargetProperty,
- float* outWhitePointNits) {
- const auto error =
- mComposer.getClientTargetProperty(mId, outClientTargetProperty, outWhitePointNits);
+Error Display::getClientTargetProperty(
+ aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness*
+ outClientTargetProperty) {
+ const auto error = mComposer.getClientTargetProperty(mId, outClientTargetProperty);
return static_cast<Error>(error);
}
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index a805566..cca20bd 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -39,6 +39,7 @@
#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
#include <aidl/android/hardware/graphics/composer3/Capability.h>
+#include <aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.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>
@@ -147,7 +148,8 @@
android::sp<android::Fence>* outPresentFence,
uint32_t* state) = 0;
[[nodiscard]] virtual std::future<hal::Error> setDisplayBrightness(
- float brightness, const Hwc2::Composer::DisplayBrightnessOptions& options) = 0;
+ float brightness, float brightnessNits,
+ const Hwc2::Composer::DisplayBrightnessOptions& options) = 0;
[[nodiscard]] virtual hal::Error setActiveConfigWithConstraints(
hal::HWConfigId configId, const hal::VsyncPeriodChangeConstraints& constraints,
hal::VsyncPeriodChangeTimeline* outTimeline) = 0;
@@ -160,7 +162,8 @@
std::vector<hal::ContentType>*) const = 0;
[[nodiscard]] virtual hal::Error setContentType(hal::ContentType) = 0;
[[nodiscard]] virtual hal::Error getClientTargetProperty(
- hal::ClientTargetProperty* outClientTargetProperty, float* outWhitePointNits) = 0;
+ aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness*
+ outClientTargetProperty) = 0;
[[nodiscard]] virtual hal::Error getDisplayDecorationSupport(
std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
support) = 0;
@@ -227,7 +230,8 @@
android::sp<android::Fence>* outPresentFence,
uint32_t* state) override;
std::future<hal::Error> setDisplayBrightness(
- float brightness, const Hwc2::Composer::DisplayBrightnessOptions& options) override;
+ float brightness, float brightnessNits,
+ const Hwc2::Composer::DisplayBrightnessOptions& options) override;
hal::Error setActiveConfigWithConstraints(hal::HWConfigId configId,
const hal::VsyncPeriodChangeConstraints& constraints,
hal::VsyncPeriodChangeTimeline* outTimeline) override;
@@ -238,8 +242,9 @@
hal::Error getSupportedContentTypes(
std::vector<hal::ContentType>* outSupportedContentTypes) const override;
hal::Error setContentType(hal::ContentType) override;
- hal::Error getClientTargetProperty(hal::ClientTargetProperty* outClientTargetProperty,
- float* outWhitePointNits) override;
+ hal::Error getClientTargetProperty(
+ aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness*
+ outClientTargetProperty) override;
hal::Error getDisplayDecorationSupport(
std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
support) override;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 459291a..79e4c75 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -479,12 +479,11 @@
RETURN_IF_HWC_ERROR_FOR("getRequests", error, displayId, BAD_INDEX);
DeviceRequestedChanges::ClientTargetProperty clientTargetProperty;
- float brightness = 1.f;
- error = hwcDisplay->getClientTargetProperty(&clientTargetProperty, &brightness);
+ error = hwcDisplay->getClientTargetProperty(&clientTargetProperty);
outChanges->emplace(DeviceRequestedChanges{std::move(changedTypes), std::move(displayRequests),
std::move(layerRequests),
- std::move(clientTargetProperty), brightness});
+ std::move(clientTargetProperty)});
error = hwcDisplay->acceptChanges();
RETURN_IF_HWC_ERROR_FOR("acceptChanges", error, displayId, BAD_INDEX);
@@ -722,12 +721,12 @@
}
std::future<status_t> HWComposer::setDisplayBrightness(
- PhysicalDisplayId displayId, float brightness,
+ PhysicalDisplayId displayId, float brightness, float brightnessNits,
const Hwc2::Composer::DisplayBrightnessOptions& options) {
RETURN_IF_INVALID_DISPLAY(displayId, ftl::yield<status_t>(BAD_INDEX));
auto& display = mDisplayData[displayId].hwcDisplay;
- return ftl::chain(display->setDisplayBrightness(brightness, options))
+ return ftl::chain(display->setDisplayBrightness(brightness, brightnessNits, options))
.then([displayId](hal::Error error) -> status_t {
if (error == hal::Error::UNSUPPORTED) {
RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 0e15a7c..7dc10ea 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -45,6 +45,7 @@
#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
#include <aidl/android/hardware/graphics/composer3/Capability.h>
+#include <aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.h>
#include <aidl/android/hardware/graphics/composer3/Composition.h>
#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
@@ -78,7 +79,8 @@
using ChangedTypes =
std::unordered_map<HWC2::Layer*,
aidl::android::hardware::graphics::composer3::Composition>;
- using ClientTargetProperty = hal::ClientTargetProperty;
+ using ClientTargetProperty =
+ aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness;
using DisplayRequests = hal::DisplayRequest;
using LayerRequests = std::unordered_map<HWC2::Layer*, hal::LayerRequest>;
@@ -86,7 +88,6 @@
DisplayRequests displayRequests;
LayerRequests layerRequests;
ClientTargetProperty clientTargetProperty;
- float clientTargetBrightness;
};
struct HWCDisplayMode {
@@ -195,7 +196,7 @@
// Sets the brightness of a display.
virtual std::future<status_t> setDisplayBrightness(
- PhysicalDisplayId, float brightness,
+ PhysicalDisplayId, float brightness, float brightnessNits,
const Hwc2::Composer::DisplayBrightnessOptions&) = 0;
// Events handling ---------------------------------------------------------
@@ -279,6 +280,13 @@
virtual Hwc2::AidlTransform getPhysicalDisplayOrientation(PhysicalDisplayId) const = 0;
};
+static inline bool operator==(const android::HWComposer::DeviceRequestedChanges& lhs,
+ const android::HWComposer::DeviceRequestedChanges& rhs) {
+ return lhs.changedTypes == rhs.changedTypes && lhs.displayRequests == rhs.displayRequests &&
+ lhs.layerRequests == rhs.layerRequests &&
+ lhs.clientTargetProperty == rhs.clientTargetProperty;
+}
+
namespace impl {
class HWComposer final : public android::HWComposer {
@@ -365,7 +373,7 @@
status_t getDisplayedContentSample(HalDisplayId, uint64_t maxFrames, uint64_t timestamp,
DisplayedFrameStats* outStats) override;
std::future<status_t> setDisplayBrightness(
- PhysicalDisplayId, float brightness,
+ PhysicalDisplayId, float brightness, float brightnessNits,
const Hwc2::Composer::DisplayBrightnessOptions&) override;
// Events handling ---------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index d9af553..2597ae6 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -37,6 +37,8 @@
#include <cinttypes>
using aidl::android::hardware::graphics::composer3::Capability;
+using aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness;
+using aidl::android::hardware::graphics::composer3::DimmingStage;
using aidl::android::hardware::graphics::composer3::DisplayCapability;
namespace android {
@@ -1113,7 +1115,7 @@
return Error::NONE;
}
-Error HidlComposer::setDisplayBrightness(Display display, float brightness,
+Error HidlComposer::setDisplayBrightness(Display display, float brightness, float,
const DisplayBrightnessOptions&) {
if (!mClient_2_3) {
return Error::UNSUPPORTED;
@@ -1302,10 +1304,17 @@
}
Error HidlComposer::getClientTargetProperty(
- Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty,
- float* outBrightness) {
- mReader.takeClientTargetProperty(display, outClientTargetProperty);
- *outBrightness = 1.f;
+ Display display, ClientTargetPropertyWithBrightness* outClientTargetProperty) {
+ IComposerClient::ClientTargetProperty property;
+ mReader.takeClientTargetProperty(display, &property);
+ outClientTargetProperty->display = display;
+ outClientTargetProperty->clientTargetProperty.dataspace =
+ static_cast<::aidl::android::hardware::graphics::common::Dataspace>(property.dataspace);
+ outClientTargetProperty->clientTargetProperty.pixelFormat =
+ static_cast<::aidl::android::hardware::graphics::common::PixelFormat>(
+ property.pixelFormat);
+ outClientTargetProperty->brightness = 1.f;
+ outClientTargetProperty->dimmingStage = DimmingStage::NONE;
return Error::NONE;
}
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
index 5869ae5..d0d3c2e 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
@@ -292,7 +292,7 @@
Error setLayerPerFrameMetadataBlobs(
Display display, Layer layer,
const std::vector<IComposerClient::PerFrameMetadataBlob>& metadata) override;
- Error setDisplayBrightness(Display display, float brightness,
+ Error setDisplayBrightness(Display display, float brightness, float brightnessNits,
const DisplayBrightnessOptions& options) override;
// Composer HAL 2.4
@@ -317,9 +317,10 @@
bool mandatory, const std::vector<uint8_t>& value) override;
V2_4::Error getLayerGenericMetadataKeys(
std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) override;
- Error getClientTargetProperty(Display display,
- IComposerClient::ClientTargetProperty* outClientTargetProperty,
- float* outBrightness) override;
+ Error getClientTargetProperty(
+ Display display,
+ aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness*
+ outClientTargetProperty) override;
// AIDL Composer HAL
Error setLayerBrightness(Display display, Layer layer, float brightness) override;
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 44c086d..659efd8 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -32,7 +32,6 @@
#include <utils/Trace.h>
#include <android/hardware/power/1.3/IPower.h>
-#include <android/hardware/power/IPower.h>
#include <android/hardware/power/IPowerHintSession.h>
#include <android/hardware/power/WorkDuration.h>
@@ -62,8 +61,6 @@
using scheduler::OneShotTimer;
-class AidlPowerHalWrapper;
-
PowerAdvisor::~PowerAdvisor() = default;
namespace {
@@ -294,259 +291,244 @@
const sp<V1_3::IPower> mPowerHal = nullptr;
};
-class AidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
-public:
- AidlPowerHalWrapper(sp<IPower> powerHal) : mPowerHal(std::move(powerHal)) {
- auto ret = mPowerHal->isModeSupported(Mode::EXPENSIVE_RENDERING, &mHasExpensiveRendering);
- if (!ret.isOk()) {
- mHasExpensiveRendering = false;
- }
-
- ret = mPowerHal->isBoostSupported(Boost::DISPLAY_UPDATE_IMMINENT,
- &mHasDisplayUpdateImminent);
- if (!ret.isOk()) {
- mHasDisplayUpdateImminent = false;
- }
-
- mSupportsPowerHint = checkPowerHintSessionSupported();
+AidlPowerHalWrapper::AidlPowerHalWrapper(sp<IPower> powerHal) : mPowerHal(std::move(powerHal)) {
+ auto ret = mPowerHal->isModeSupported(Mode::EXPENSIVE_RENDERING, &mHasExpensiveRendering);
+ if (!ret.isOk()) {
+ mHasExpensiveRendering = false;
}
- ~AidlPowerHalWrapper() override {
- if (mPowerHintSession != nullptr) {
- mPowerHintSession->close();
- mPowerHintSession = nullptr;
- }
- };
-
- static std::unique_ptr<HalWrapper> connect() {
- // This only waits if the service is actually declared
- sp<IPower> powerHal = waitForVintfService<IPower>();
- if (powerHal == nullptr) {
- return nullptr;
- }
- ALOGI("Loaded AIDL Power HAL service");
-
- return std::make_unique<AidlPowerHalWrapper>(std::move(powerHal));
+ ret = mPowerHal->isBoostSupported(Boost::DISPLAY_UPDATE_IMMINENT, &mHasDisplayUpdateImminent);
+ if (!ret.isOk()) {
+ mHasDisplayUpdateImminent = false;
}
- bool setExpensiveRendering(bool enabled) override {
- ALOGV("AIDL setExpensiveRendering %s", enabled ? "T" : "F");
- if (!mHasExpensiveRendering) {
- ALOGV("Skipped sending EXPENSIVE_RENDERING because HAL doesn't support it");
- return true;
- }
+ mSupportsPowerHint = checkPowerHintSessionSupported();
+}
- auto ret = mPowerHal->setMode(Mode::EXPENSIVE_RENDERING, enabled);
- if (ret.isOk()) {
- traceExpensiveRendering(enabled);
- }
- return ret.isOk();
+AidlPowerHalWrapper::~AidlPowerHalWrapper() {
+ if (mPowerHintSession != nullptr) {
+ mPowerHintSession->close();
+ mPowerHintSession = nullptr;
}
-
- bool notifyDisplayUpdateImminent() override {
- ALOGV("AIDL notifyDisplayUpdateImminent");
- if (!mHasDisplayUpdateImminent) {
- ALOGV("Skipped sending DISPLAY_UPDATE_IMMINENT because HAL doesn't support it");
- return true;
- }
-
- auto ret = mPowerHal->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 0);
- return ret.isOk();
- }
-
- // only version 2+ of the aidl supports power hint sessions, hidl has no support
- bool supportsPowerHintSession() override { return mSupportsPowerHint; }
-
- bool checkPowerHintSessionSupported() {
- int64_t unused;
- // Try to get preferred rate to determine if hint sessions are supported
- // We check for isOk not EX_UNSUPPORTED_OPERATION to lump other errors
- return mPowerHal->getHintSessionPreferredRate(&unused).isOk();
- }
-
- bool isPowerHintSessionRunning() override { return mPowerHintSession != nullptr; }
-
- void closePowerHintSession() {
- if (mPowerHintSession != nullptr) {
- mPowerHintSession->close();
- mPowerHintSession = nullptr;
- }
- }
-
- void restartPowerHintSession() {
- closePowerHintSession();
- startPowerHintSession();
- }
-
- void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) override {
- if (threadIds != mPowerHintThreadIds) {
- mPowerHintThreadIds = threadIds;
- if (isPowerHintSessionRunning()) {
- restartPowerHintSession();
- }
- }
- }
-
- bool startPowerHintSession() override {
- if (mPowerHintSession != nullptr || mPowerHintThreadIds.empty()) {
- ALOGV("Cannot start power hint session, skipping");
- return false;
- }
- auto ret = mPowerHal->createHintSession(getpid(), static_cast<int32_t>(getuid()),
- mPowerHintThreadIds, mTargetDuration,
- &mPowerHintSession);
- if (!ret.isOk()) {
- ALOGW("Failed to start power hint session with error: %s",
- ret.exceptionToString(ret.exceptionCode()).c_str());
- } else {
- mLastTargetDurationSent = mTargetDuration;
- }
- return isPowerHintSessionRunning();
- }
-
- bool shouldSetTargetDuration(int64_t targetDurationNanos) {
- // report if the change in target from our last submission to now exceeds the threshold
- return abs(1.0 -
- static_cast<double>(mLastTargetDurationSent) /
- static_cast<double>(targetDurationNanos)) >=
- kAllowedTargetDeviationPercent;
- }
-
- void setTargetWorkDuration(int64_t targetDurationNanos) override {
- ATRACE_CALL();
- mTargetDuration = targetDurationNanos;
- if (sTraceHintSessionData) ATRACE_INT64("Time target", targetDurationNanos);
- if (!sNormalizeTarget && shouldSetTargetDuration(targetDurationNanos) &&
- isPowerHintSessionRunning()) {
- if (mLastActualDurationSent.has_value()) {
- // update the error term here since we are actually sending an update to powerhal
- if (sTraceHintSessionData)
- ATRACE_INT64("Target error term",
- targetDurationNanos - *mLastActualDurationSent);
- }
- ALOGV("Sending target time: %lld ns", static_cast<long long>(targetDurationNanos));
- mLastTargetDurationSent = targetDurationNanos;
- auto ret = mPowerHintSession->updateTargetWorkDuration(targetDurationNanos);
- if (!ret.isOk()) {
- ALOGW("Failed to set power hint target work duration with error: %s",
- ret.exceptionMessage().c_str());
- mShouldReconnectHal = true;
- }
- }
- }
-
- bool shouldReportActualDurationsNow() {
- // report if we have never reported before or are approaching a stale session
- if (!mLastActualDurationSent.has_value() ||
- (systemTime() - mLastActualReportTimestamp) > kStaleTimeout.count()) {
- return true;
- }
-
- if (!mActualDuration.has_value()) {
- return false;
- }
-
- // duration of most recent timing
- const double mostRecentActualDuration = static_cast<double>(*mActualDuration);
- // duration of the last timing actually reported to the powerhal
- const double lastReportedActualDuration = static_cast<double>(*mLastActualDurationSent);
-
- // report if the change in duration from then to now exceeds the threshold
- return abs(1.0 - mostRecentActualDuration / lastReportedActualDuration) >=
- kAllowedActualDeviationPercent;
- }
-
- void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timeStampNanos) override {
- ATRACE_CALL();
-
- if (actualDurationNanos < 0 || !isPowerHintSessionRunning()) {
- ALOGV("Failed to send actual work duration, skipping");
- return;
- }
-
- WorkDuration duration;
- duration.durationNanos = actualDurationNanos;
- mActualDuration = actualDurationNanos;
-
- // normalize the sent values to a pre-set target
- if (sNormalizeTarget) {
- duration.durationNanos += mLastTargetDurationSent - mTargetDuration;
- }
- duration.timeStampNanos = timeStampNanos;
- mPowerHintQueue.push_back(duration);
-
- long long targetNsec = mTargetDuration;
- long long durationNsec = actualDurationNanos;
-
- if (sTraceHintSessionData) {
- ATRACE_INT64("Measured duration", durationNsec);
- ATRACE_INT64("Target error term", targetNsec - durationNsec);
- }
-
- ALOGV("Sending actual work duration of: %lld on target: %lld with error: %lld",
- durationNsec, targetNsec, targetNsec - durationNsec);
-
- // This rate limiter queues similar duration reports to the powerhal into
- // batches to avoid excessive binder calls. The criteria to send a given batch
- // are outlined in shouldReportActualDurationsNow()
- if (shouldReportActualDurationsNow()) {
- ALOGV("Sending hint update batch");
- mLastActualReportTimestamp = systemTime();
- auto ret = mPowerHintSession->reportActualWorkDuration(mPowerHintQueue);
- if (!ret.isOk()) {
- ALOGW("Failed to report actual work durations with error: %s",
- ret.exceptionMessage().c_str());
- mShouldReconnectHal = true;
- }
- mPowerHintQueue.clear();
- // we save the non-normalized value here to detect % changes
- mLastActualDurationSent = actualDurationNanos;
- }
- }
-
- bool shouldReconnectHAL() override { return mShouldReconnectHal; }
-
- std::vector<int32_t> getPowerHintSessionThreadIds() override { return mPowerHintThreadIds; }
-
- std::optional<int64_t> getTargetWorkDuration() override { return mTargetDuration; }
-
-private:
- const sp<IPower> mPowerHal = nullptr;
- bool mHasExpensiveRendering = false;
- bool mHasDisplayUpdateImminent = false;
- // Used to indicate an error state and need for reconstruction
- bool mShouldReconnectHal = false;
- // This is not thread safe, but is currently protected by mPowerHalMutex so it needs no lock
- sp<IPowerHintSession> mPowerHintSession = nullptr;
- // Queue of actual durations saved to report
- std::vector<WorkDuration> mPowerHintQueue;
- // The latest un-normalized values we have received for target and actual
- int64_t mTargetDuration = kDefaultTarget.count();
- std::optional<int64_t> mActualDuration;
- // The list of thread ids, stored so we can restart the session from this class if needed
- std::vector<int32_t> mPowerHintThreadIds;
- bool mSupportsPowerHint;
- // Keep track of the last messages sent for rate limiter change detection
- std::optional<int64_t> mLastActualDurationSent;
- // timestamp of the last report we sent, used to avoid stale sessions
- int64_t mLastActualReportTimestamp = 0;
- int64_t mLastTargetDurationSent = kDefaultTarget.count();
- // Whether to normalize all the actual values as error terms relative to a constant target
- // This saves a binder call by not setting the target, and should not affect the pid values
- static const bool sNormalizeTarget;
- // Whether we should emit ATRACE_INT data for hint sessions
- static const bool sTraceHintSessionData;
- // Max percent the actual duration can vary without causing a report (eg: 0.1 = 10%)
- static constexpr double kAllowedActualDeviationPercent = 0.1;
- // Max percent the target duration can vary without causing a report (eg: 0.05 = 5%)
- static constexpr double kAllowedTargetDeviationPercent = 0.05;
- // Target used for init and normalization, the actual value does not really matter
- static constexpr const std::chrono::nanoseconds kDefaultTarget = 50ms;
- // Amount of time after the last message was sent before the session goes stale
- // actually 100ms but we use 80 here to ideally avoid going stale
- static constexpr const std::chrono::nanoseconds kStaleTimeout = 80ms;
};
+std::unique_ptr<PowerAdvisor::HalWrapper> AidlPowerHalWrapper::connect() {
+ // This only waits if the service is actually declared
+ sp<IPower> powerHal = waitForVintfService<IPower>();
+ if (powerHal == nullptr) {
+ return nullptr;
+ }
+ ALOGI("Loaded AIDL Power HAL service");
+
+ return std::make_unique<AidlPowerHalWrapper>(std::move(powerHal));
+}
+
+bool AidlPowerHalWrapper::setExpensiveRendering(bool enabled) {
+ ALOGV("AIDL setExpensiveRendering %s", enabled ? "T" : "F");
+ if (!mHasExpensiveRendering) {
+ ALOGV("Skipped sending EXPENSIVE_RENDERING because HAL doesn't support it");
+ return true;
+ }
+
+ auto ret = mPowerHal->setMode(Mode::EXPENSIVE_RENDERING, enabled);
+ if (ret.isOk()) {
+ traceExpensiveRendering(enabled);
+ }
+ return ret.isOk();
+}
+
+bool AidlPowerHalWrapper::notifyDisplayUpdateImminent() {
+ ALOGV("AIDL notifyDisplayUpdateImminent");
+ if (!mHasDisplayUpdateImminent) {
+ ALOGV("Skipped sending DISPLAY_UPDATE_IMMINENT because HAL doesn't support it");
+ return true;
+ }
+
+ auto ret = mPowerHal->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 0);
+ return ret.isOk();
+}
+
+// only version 2+ of the aidl supports power hint sessions, hidl has no support
+bool AidlPowerHalWrapper::supportsPowerHintSession() {
+ return mSupportsPowerHint;
+}
+
+bool AidlPowerHalWrapper::checkPowerHintSessionSupported() {
+ int64_t unused;
+ // Try to get preferred rate to determine if hint sessions are supported
+ // We check for isOk not EX_UNSUPPORTED_OPERATION to lump together errors
+ return mPowerHal->getHintSessionPreferredRate(&unused).isOk();
+}
+
+bool AidlPowerHalWrapper::isPowerHintSessionRunning() {
+ return mPowerHintSession != nullptr;
+}
+
+void AidlPowerHalWrapper::closePowerHintSession() {
+ if (mPowerHintSession != nullptr) {
+ mPowerHintSession->close();
+ mPowerHintSession = nullptr;
+ }
+}
+
+void AidlPowerHalWrapper::restartPowerHintSession() {
+ closePowerHintSession();
+ startPowerHintSession();
+}
+
+void AidlPowerHalWrapper::setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) {
+ if (threadIds != mPowerHintThreadIds) {
+ mPowerHintThreadIds = threadIds;
+ if (isPowerHintSessionRunning()) {
+ restartPowerHintSession();
+ }
+ }
+}
+
+bool AidlPowerHalWrapper::startPowerHintSession() {
+ if (mPowerHintSession != nullptr || mPowerHintThreadIds.empty()) {
+ ALOGV("Cannot start power hint session, skipping");
+ return false;
+ }
+ auto ret =
+ mPowerHal->createHintSession(getpid(), static_cast<int32_t>(getuid()),
+ mPowerHintThreadIds, mTargetDuration, &mPowerHintSession);
+ if (!ret.isOk()) {
+ ALOGW("Failed to start power hint session with error: %s",
+ ret.exceptionToString(ret.exceptionCode()).c_str());
+ } else {
+ mLastTargetDurationSent = mTargetDuration;
+ }
+ return isPowerHintSessionRunning();
+}
+
+bool AidlPowerHalWrapper::shouldSetTargetDuration(int64_t targetDurationNanos) {
+ if (targetDurationNanos <= 0) {
+ return false;
+ }
+ // report if the change in target from our last submission to now exceeds the threshold
+ return abs(1.0 -
+ static_cast<double>(mLastTargetDurationSent) /
+ static_cast<double>(targetDurationNanos)) >= kAllowedTargetDeviationPercent;
+}
+
+void AidlPowerHalWrapper::setTargetWorkDuration(int64_t targetDurationNanos) {
+ ATRACE_CALL();
+ mTargetDuration = targetDurationNanos;
+ if (sTraceHintSessionData) ATRACE_INT64("Time target", targetDurationNanos);
+ if (!sNormalizeTarget && isPowerHintSessionRunning() &&
+ shouldSetTargetDuration(targetDurationNanos)) {
+ if (mLastActualDurationSent.has_value()) {
+ // update the error term here since we are actually sending an update to powerhal
+ if (sTraceHintSessionData)
+ ATRACE_INT64("Target error term", targetDurationNanos - *mLastActualDurationSent);
+ }
+ ALOGV("Sending target time: %" PRId64 "ns", targetDurationNanos);
+ mLastTargetDurationSent = targetDurationNanos;
+ auto ret = mPowerHintSession->updateTargetWorkDuration(targetDurationNanos);
+ if (!ret.isOk()) {
+ ALOGW("Failed to set power hint target work duration with error: %s",
+ ret.exceptionMessage().c_str());
+ mShouldReconnectHal = true;
+ }
+ }
+}
+
+bool AidlPowerHalWrapper::shouldReportActualDurationsNow() {
+ // report if we have never reported before or are approaching a stale session
+ if (!mLastActualDurationSent.has_value() ||
+ (systemTime() - mLastActualReportTimestamp) > kStaleTimeout.count()) {
+ return true;
+ }
+
+ if (!mActualDuration.has_value()) {
+ return false;
+ }
+
+ // duration of most recent timing
+ const double mostRecentActualDuration = static_cast<double>(*mActualDuration);
+ // duration of the last timing actually reported to the powerhal
+ const double lastReportedActualDuration = static_cast<double>(*mLastActualDurationSent);
+
+ // report if the change in duration from then to now exceeds the threshold
+ return abs(1.0 - mostRecentActualDuration / lastReportedActualDuration) >=
+ kAllowedActualDeviationPercent;
+}
+
+void AidlPowerHalWrapper::sendActualWorkDuration(int64_t actualDurationNanos,
+ nsecs_t timeStampNanos) {
+ ATRACE_CALL();
+
+ if (actualDurationNanos < 0 || !isPowerHintSessionRunning()) {
+ ALOGV("Failed to send actual work duration, skipping");
+ return;
+ }
+ nsecs_t reportedDuration = actualDurationNanos;
+
+ // normalize the sent values to a pre-set target
+ if (sNormalizeTarget) {
+ reportedDuration += mLastTargetDurationSent - mTargetDuration;
+ } else {
+ // when target duration change is within deviation and not updated, adjust the actual
+ // duration proportionally based on the difference, e.g. if new target is 5ms longer than
+ // last reported but actual duration is the same as last target, we want to report a smaller
+ // actual work duration now to indicate that we are overshooting
+ if (mLastTargetDurationSent != kDefaultTarget.count() && mTargetDuration != 0) {
+ reportedDuration =
+ static_cast<int64_t>(static_cast<long double>(mLastTargetDurationSent) /
+ mTargetDuration * actualDurationNanos);
+ mActualDuration = reportedDuration;
+ }
+ }
+ mActualDuration = reportedDuration;
+ WorkDuration duration;
+ duration.durationNanos = reportedDuration;
+ duration.timeStampNanos = timeStampNanos;
+ mPowerHintQueue.push_back(duration);
+
+ if (sTraceHintSessionData) {
+ ATRACE_INT64("Measured duration", actualDurationNanos);
+ ATRACE_INT64("Target error term", mTargetDuration - actualDurationNanos);
+
+ ATRACE_INT64("Reported duration", reportedDuration);
+ ATRACE_INT64("Reported target", mLastTargetDurationSent);
+ ATRACE_INT64("Reported target error term", mLastTargetDurationSent - reportedDuration);
+ }
+
+ ALOGV("Sending actual work duration of: %" PRId64 " on reported target: %" PRId64
+ " with error: %" PRId64,
+ reportedDuration, mLastTargetDurationSent, mLastTargetDurationSent - reportedDuration);
+
+ // This rate limiter queues similar duration reports to the powerhal into
+ // batches to avoid excessive binder calls. The criteria to send a given batch
+ // are outlined in shouldReportActualDurationsNow()
+ if (shouldReportActualDurationsNow()) {
+ ALOGV("Sending hint update batch");
+ mLastActualReportTimestamp = systemTime();
+ auto ret = mPowerHintSession->reportActualWorkDuration(mPowerHintQueue);
+ if (!ret.isOk()) {
+ ALOGW("Failed to report actual work durations with error: %s",
+ ret.exceptionMessage().c_str());
+ mShouldReconnectHal = true;
+ }
+ mPowerHintQueue.clear();
+ // we save the non-normalized value here to detect % changes
+ mLastActualDurationSent = reportedDuration;
+ }
+}
+
+bool AidlPowerHalWrapper::shouldReconnectHAL() {
+ return mShouldReconnectHal;
+}
+
+std::vector<int32_t> AidlPowerHalWrapper::getPowerHintSessionThreadIds() {
+ return mPowerHintThreadIds;
+}
+
+std::optional<int64_t> AidlPowerHalWrapper::getTargetWorkDuration() {
+ return mTargetDuration;
+}
+
const bool AidlPowerHalWrapper::sTraceHintSessionData =
base::GetBoolProperty(std::string("debug.sf.trace_hint_sessions"), false);
@@ -582,6 +564,7 @@
if (!wrapper->shouldReconnectHAL()) {
return wrapper;
}
+ ALOGD("Reconnecting Power HAL");
sHalWrapper = nullptr;
}
@@ -594,7 +577,9 @@
// If that didn't succeed, attempt to connect to the HIDL Power HAL
if (sHalWrapper == nullptr) {
sHalWrapper = HidlPowerHalWrapper::connect();
- } else { // if AIDL, pass on any existing hint session values
+ } else {
+ ALOGD("Successfully connecting AIDL Power HAL");
+ // if AIDL, pass on any existing hint session values
// thread ids always safe to set
sHalWrapper->setPowerHintSessionThreadIds(oldPowerHintSessionThreadIds);
// only set duration and start if duration is defined
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
index 0db56aa..61bb32b 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -22,6 +22,7 @@
#include <utils/Mutex.h>
+#include <android/hardware/power/IPower.h>
#include <ui/DisplayIdentification.h>
#include "../Scheduler/OneShotTimer.h"
@@ -118,6 +119,69 @@
scheduler::OneShotTimer mScreenUpdateTimer;
};
+class AidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
+public:
+ explicit AidlPowerHalWrapper(sp<hardware::power::IPower> powerHal);
+ ~AidlPowerHalWrapper() override;
+
+ static std::unique_ptr<HalWrapper> connect();
+
+ bool setExpensiveRendering(bool enabled) override;
+ bool notifyDisplayUpdateImminent() override;
+ bool supportsPowerHintSession() override;
+ bool isPowerHintSessionRunning() override;
+ void restartPowerHintSession() override;
+ void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) override;
+ bool startPowerHintSession() override;
+ void setTargetWorkDuration(int64_t targetDurationNanos) override;
+ void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timeStampNanos) override;
+ bool shouldReconnectHAL() override;
+ std::vector<int32_t> getPowerHintSessionThreadIds() override;
+ std::optional<int64_t> getTargetWorkDuration() override;
+
+private:
+ bool checkPowerHintSessionSupported();
+ void closePowerHintSession();
+ bool shouldReportActualDurationsNow();
+ bool shouldSetTargetDuration(int64_t targetDurationNanos);
+
+ const sp<hardware::power::IPower> mPowerHal = nullptr;
+ bool mHasExpensiveRendering = false;
+ bool mHasDisplayUpdateImminent = false;
+ // Used to indicate an error state and need for reconstruction
+ bool mShouldReconnectHal = false;
+ // This is not thread safe, but is currently protected by mPowerHalMutex so it needs no lock
+ sp<hardware::power::IPowerHintSession> mPowerHintSession = nullptr;
+ // Queue of actual durations saved to report
+ std::vector<hardware::power::WorkDuration> mPowerHintQueue;
+ // The latest un-normalized values we have received for target and actual
+ int64_t mTargetDuration = kDefaultTarget.count();
+ std::optional<int64_t> mActualDuration;
+ // The list of thread ids, stored so we can restart the session from this class if needed
+ std::vector<int32_t> mPowerHintThreadIds;
+ bool mSupportsPowerHint;
+ // Keep track of the last messages sent for rate limiter change detection
+ std::optional<int64_t> mLastActualDurationSent;
+ // timestamp of the last report we sent, used to avoid stale sessions
+ int64_t mLastActualReportTimestamp = 0;
+ int64_t mLastTargetDurationSent = kDefaultTarget.count();
+ // Whether to normalize all the actual values as error terms relative to a constant target
+ // This saves a binder call by not setting the target, and should not affect the pid values
+ static const bool sNormalizeTarget;
+ // Whether we should emit ATRACE_INT data for hint sessions
+ static const bool sTraceHintSessionData;
+
+ // Max percent the actual duration can vary without causing a report (eg: 0.1 = 10%)
+ static constexpr double kAllowedActualDeviationPercent = 0.1;
+ // Max percent the target duration can vary without causing a report (eg: 0.1 = 10%)
+ static constexpr double kAllowedTargetDeviationPercent = 0.1;
+ // Target used for init and normalization, the actual value does not really matter
+ static constexpr const std::chrono::nanoseconds kDefaultTarget = 50ms;
+ // Amount of time after the last message was sent before the session goes stale
+ // actually 100ms but we use 80 here to ideally avoid going stale
+ static constexpr const std::chrono::nanoseconds kStaleTimeout = 80ms;
+};
+
} // namespace impl
} // namespace Hwc2
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index b4fb51f..3803a78 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -19,20 +19,20 @@
#pragma clang diagnostic ignored "-Wconversion"
// #define LOG_NDEBUG 0
-#include "VirtualDisplaySurface.h"
#include <cinttypes>
-#include "HWComposer.h"
-#include "SurfaceFlinger.h"
-
-#include <ftl/Flags.h>
#include <ftl/enum.h>
+#include <ftl/flags.h>
#include <gui/BufferItem.h>
#include <gui/BufferQueue.h>
#include <gui/IProducerListener.h>
#include <system/window.h>
+#include "HWComposer.h"
+#include "SurfaceFlinger.h"
+#include "VirtualDisplaySurface.h"
+
#define VDS_LOGE(msg, ...) ALOGE("[%s] " msg, \
mDisplayName.c_str(), ##__VA_ARGS__)
#define VDS_LOGW_IF(cond, msg, ...) ALOGW_IF(cond, "[%s] " msg, \
@@ -657,7 +657,7 @@
std::string VirtualDisplaySurface::toString(CompositionType type) {
using namespace std::literals;
- return type == CompositionType::Unknown ? "Unknown"s : Flags(type).string();
+ return type == CompositionType::Unknown ? "Unknown"s : ftl::Flags(type).string();
}
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 307da41..e21095a 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -89,6 +89,9 @@
virtual void dumpAsString(String8& result) const;
virtual void resizeBuffers(const ui::Size&) override;
virtual const sp<Fence>& getClientTargetAcquireFence() const override;
+ // Virtual display surface needs to prepare the frame based on composition type. Skip
+ // any client composition prediction.
+ virtual bool supportsCompositionStrategyPrediction() const override { return false; };
private:
enum Source : size_t {
diff --git a/services/surfaceflinger/EffectLayer.cpp b/services/surfaceflinger/EffectLayer.cpp
index cc85352..e8c590e 100644
--- a/services/surfaceflinger/EffectLayer.cpp
+++ b/services/surfaceflinger/EffectLayer.cpp
@@ -114,7 +114,13 @@
}
sp<compositionengine::LayerFE> EffectLayer::getCompositionEngineLayerFE() const {
- return asLayerFE();
+ // There's no need to get a CE Layer if the EffectLayer isn't going to draw anything. In that
+ // case, it acts more like a ContainerLayer so returning a null CE Layer makes more sense
+ if (hasSomethingToDraw()) {
+ return asLayerFE();
+ } else {
+ return nullptr;
+ }
}
compositionengine::LayerFECompositionState* EffectLayer::editCompositionState() {
diff --git a/services/surfaceflinger/FlagManager.cpp b/services/surfaceflinger/FlagManager.cpp
index bd3cf74..f8ad8f6 100644
--- a/services/surfaceflinger/FlagManager.cpp
+++ b/services/surfaceflinger/FlagManager.cpp
@@ -96,7 +96,8 @@
}
bool FlagManager::use_adpf_cpu_hint() const {
- std::optional<bool> sysPropVal = std::nullopt;
+ std::optional<bool> sysPropVal =
+ doParse<bool>(base::GetProperty("debug.sf.enable_adpf_cpu_hint", "").c_str());
return getValue("AdpfFeature__adpf_cpu_hint", sysPropVal, false);
}
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index fa5a1c8..3a92ca4 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -37,6 +37,7 @@
#include <cutils/native_handle.h>
#include <cutils/properties.h>
#include <ftl/enum.h>
+#include <ftl/fake_guard.h>
#include <gui/BufferItem.h>
#include <gui/LayerDebugInfo.h>
#include <gui/Surface.h>
@@ -81,11 +82,13 @@
constexpr int kDumpTableRowLength = 159;
} // namespace
+using namespace ftl::flag_operators;
+
using base::StringAppendF;
-using namespace android::flag_operators;
-using PresentState = frametimeline::SurfaceFrame::PresentState;
using gui::WindowInfo;
+using PresentState = frametimeline::SurfaceFrame::PresentState;
+
std::atomic<int32_t> Layer::sSequence{1};
Layer::Layer(const LayerCreationArgs& args)
@@ -139,6 +142,7 @@
mDrawingState.destinationFrame.makeInvalid();
mDrawingState.isTrustedOverlay = false;
mDrawingState.dropInputMode = gui::DropInputMode::NONE;
+ mDrawingState.dimmingEnabled = true;
if (args.flags & ISurfaceComposerClient::eNoColorFill) {
// Set an invalid color so there is no color fill.
@@ -477,6 +481,7 @@
compositionState->colorTransformIsIdentity = !hasColorTransform();
compositionState->surfaceDamage = surfaceDamageRegion;
compositionState->hasProtectedContent = isProtected();
+ compositionState->dimmingEnabled = isDimmingEnabled();
const bool usesRoundedCorners = getRoundedCornerState().radius != 0.f;
@@ -1038,6 +1043,16 @@
return true;
}
+bool Layer::setDimmingEnabled(const bool dimmingEnabled) {
+ if (mDrawingState.dimmingEnabled == dimmingEnabled) return false;
+
+ mDrawingState.sequence++;
+ mDrawingState.dimmingEnabled = dimmingEnabled;
+ mDrawingState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
bool Layer::setFrameRateSelectionPriority(int32_t priority) {
if (mDrawingState.frameRateSelectionPriority == priority) return false;
mDrawingState.frameRateSelectionPriority = priority;
@@ -2045,10 +2060,10 @@
writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags);
if (traceFlags & LayerTracing::TRACE_COMPOSITION) {
+ ftl::FakeGuard guard(mFlinger->mStateLock); // Called from the main thread.
+
// Only populate for the primary display.
- UnnecessaryLock assumeLocked(mFlinger->mStateLock); // called from the main thread.
- const auto display = mFlinger->getDefaultDisplayDeviceLocked();
- if (display) {
+ if (const auto display = mFlinger->getDefaultDisplayDeviceLocked()) {
const auto compositionType = getCompositionType(*display);
layerProto->set_hwc_composition_type(static_cast<HwcCompositionType>(compositionType));
LayerProtoHelper::writeToProto(getVisibleRegion(display.get()),
@@ -2170,7 +2185,7 @@
layerInfo->set_owner_uid(mOwnerUid);
- if (traceFlags & LayerTracing::TRACE_INPUT) {
+ if ((traceFlags & LayerTracing::TRACE_INPUT) && needsInputInfo()) {
WindowInfo info;
if (useDrawing) {
info = fillInputInfo(ui::Transform(), /* displayIsSecure */ true);
@@ -2581,6 +2596,8 @@
return FrameRateCompatibility::ExactOrMultiple;
case ANATIVEWINDOW_FRAME_RATE_EXACT:
return FrameRateCompatibility::Exact;
+ case ANATIVEWINDOW_FRAME_RATE_NO_VOTE:
+ return FrameRateCompatibility::NoVote;
default:
LOG_ALWAYS_FATAL("Invalid frame rate compatibility value %d", compatibility);
return FrameRateCompatibility::Default;
@@ -2647,6 +2664,18 @@
mDrawingState.callbackHandles = {};
}
+bool Layer::setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& handles) {
+ if (handles.empty()) {
+ return false;
+ }
+
+ for (const auto& handle : handles) {
+ mFlinger->getTransactionCallbackInvoker().registerUnpresentedCallbackHandle(handle);
+ }
+
+ return true;
+}
+
// ---------------------------------------------------------------------------
std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 846460d..ecea744 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -281,6 +281,8 @@
gui::DropInputMode dropInputMode;
bool autoRefresh = false;
+
+ bool dimmingEnabled = true;
};
/*
@@ -411,6 +413,7 @@
virtual mat4 getColorTransform() const;
virtual bool hasColorTransform() const;
virtual bool isColorSpaceAgnostic() const { return mDrawingState.colorSpaceAgnostic; }
+ virtual bool isDimmingEnabled() const { return getDrawingState().dimmingEnabled; };
// Used only to set BufferStateLayer state
virtual bool setTransform(uint32_t /*transform*/) { return false; };
@@ -428,15 +431,14 @@
virtual bool setApi(int32_t /*api*/) { return false; };
virtual bool setSidebandStream(const sp<NativeHandle>& /*sidebandStream*/) { return false; };
virtual bool setTransactionCompletedListeners(
- const std::vector<sp<CallbackHandle>>& /*handles*/) {
- return false;
- };
+ const std::vector<sp<CallbackHandle>>& /*handles*/);
virtual bool addFrameEvent(const sp<Fence>& /*acquireFence*/, nsecs_t /*postedTime*/,
nsecs_t /*requestedPresentTime*/) {
return false;
}
virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace);
virtual bool setColorSpaceAgnostic(const bool agnostic);
+ virtual bool setDimmingEnabled(const bool dimmingEnabled);
virtual bool setFrameRateSelectionPriority(int32_t priority);
virtual bool setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint);
virtual void setAutoRefresh(bool /* autoRefresh */) {}
diff --git a/services/surfaceflinger/MainThreadGuard.h b/services/surfaceflinger/MainThreadGuard.h
deleted file mode 100644
index c1aa118..0000000
--- a/services/surfaceflinger/MainThreadGuard.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.
- */
-
-#pragma once
-
-#include <utils/Mutex.h>
-
-namespace android {
-namespace {
-
-// Helps to ensure that some functions runs on SF's main thread by using the
-// clang thread safety annotations.
-class CAPABILITY("mutex") MainThreadGuard {
-} SF_MAIN_THREAD;
-
-struct SCOPED_CAPABILITY MainThreadScopedGuard {
-public:
- explicit MainThreadScopedGuard(MainThreadGuard& mutex) ACQUIRE(mutex) {}
- ~MainThreadScopedGuard() RELEASE() {}
-};
-} // namespace
-} // namespace android
diff --git a/services/surfaceflinger/MutexUtils.h b/services/surfaceflinger/MutexUtils.h
new file mode 100644
index 0000000..f8be6f3
--- /dev/null
+++ b/services/surfaceflinger/MutexUtils.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <log/log.h>
+#include <utils/Mutex.h>
+
+namespace android {
+
+struct SCOPED_CAPABILITY ConditionalLock {
+ ConditionalLock(Mutex& mutex, bool lock) ACQUIRE(mutex) : mutex(mutex), lock(lock) {
+ if (lock) mutex.lock();
+ }
+
+ ~ConditionalLock() RELEASE() {
+ if (lock) mutex.unlock();
+ }
+
+ Mutex& mutex;
+ const bool lock;
+};
+
+struct SCOPED_CAPABILITY TimedLock {
+ TimedLock(Mutex& mutex, nsecs_t timeout, const char* whence) ACQUIRE(mutex)
+ : mutex(mutex), status(mutex.timedLock(timeout)) {
+ ALOGE_IF(!locked(), "%s timed out locking: %s (%d)", whence, strerror(-status), status);
+ }
+
+ ~TimedLock() RELEASE() {
+ if (locked()) mutex.unlock();
+ }
+
+ bool locked() const { return status == NO_ERROR; }
+
+ Mutex& mutex;
+ const status_t status;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index 81c1566..d4435c2 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -14,22 +14,20 @@
* limitations under the License.
*/
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-#pragma clang diagnostic ignored "-Wextra"
-
#include <algorithm>
#include "RefreshRateOverlay.h"
#include "Client.h"
#include "Layer.h"
-#include <SkBlendMode.h>
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+#include <SkCanvas.h>
#include <SkPaint.h>
+#pragma clang diagnostic pop
+#include <SkBlendMode.h>
#include <SkRect.h>
#include <SkSurface.h>
-#include <gui/IProducerListener.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/SurfaceControl.h>
@@ -37,29 +35,49 @@
#define LOG_TAG "RefreshRateOverlay"
namespace android {
+namespace {
-void RefreshRateOverlay::SevenSegmentDrawer::drawSegment(Segment segment, int left, SkColor& color,
+constexpr int kDigitWidth = 64;
+constexpr int kDigitHeight = 100;
+constexpr int kDigitSpace = 16;
+
+// Layout is digit, space, digit, space, digit, space, spinner.
+constexpr int kBufferWidth = 4 * kDigitWidth + 3 * kDigitSpace;
+constexpr int kBufferHeight = kDigitHeight;
+
+SurfaceComposerClient::Transaction createTransaction(const sp<SurfaceControl>& surface) {
+ constexpr float kFrameRate = 0.f;
+ constexpr int8_t kCompatibility = ANATIVEWINDOW_FRAME_RATE_NO_VOTE;
+ constexpr int8_t kSeamlessness = ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS;
+
+ return SurfaceComposerClient::Transaction().setFrameRate(surface, kFrameRate, kCompatibility,
+ kSeamlessness);
+}
+
+} // namespace
+
+void RefreshRateOverlay::SevenSegmentDrawer::drawSegment(Segment segment, int left, SkColor color,
SkCanvas& canvas) {
const SkRect rect = [&]() {
switch (segment) {
case Segment::Upper:
- return SkRect::MakeLTRB(left, 0, left + DIGIT_WIDTH, DIGIT_SPACE);
+ return SkRect::MakeLTRB(left, 0, left + kDigitWidth, kDigitSpace);
case Segment::UpperLeft:
- return SkRect::MakeLTRB(left, 0, left + DIGIT_SPACE, DIGIT_HEIGHT / 2);
+ return SkRect::MakeLTRB(left, 0, left + kDigitSpace, kDigitHeight / 2);
case Segment::UpperRight:
- return SkRect::MakeLTRB(left + DIGIT_WIDTH - DIGIT_SPACE, 0, left + DIGIT_WIDTH,
- DIGIT_HEIGHT / 2);
+ return SkRect::MakeLTRB(left + kDigitWidth - kDigitSpace, 0, left + kDigitWidth,
+ kDigitHeight / 2);
case Segment::Middle:
- return SkRect::MakeLTRB(left, DIGIT_HEIGHT / 2 - DIGIT_SPACE / 2,
- left + DIGIT_WIDTH, DIGIT_HEIGHT / 2 + DIGIT_SPACE / 2);
+ return SkRect::MakeLTRB(left, kDigitHeight / 2 - kDigitSpace / 2,
+ left + kDigitWidth, kDigitHeight / 2 + kDigitSpace / 2);
case Segment::LowerLeft:
- return SkRect::MakeLTRB(left, DIGIT_HEIGHT / 2, left + DIGIT_SPACE, DIGIT_HEIGHT);
+ return SkRect::MakeLTRB(left, kDigitHeight / 2, left + kDigitSpace, kDigitHeight);
case Segment::LowerRight:
- return SkRect::MakeLTRB(left + DIGIT_WIDTH - DIGIT_SPACE, DIGIT_HEIGHT / 2,
- left + DIGIT_WIDTH, DIGIT_HEIGHT);
+ return SkRect::MakeLTRB(left + kDigitWidth - kDigitSpace, kDigitHeight / 2,
+ left + kDigitWidth, kDigitHeight);
case Segment::Bottom:
- return SkRect::MakeLTRB(left, DIGIT_HEIGHT - DIGIT_SPACE, left + DIGIT_WIDTH,
- DIGIT_HEIGHT);
+ return SkRect::MakeLTRB(left, kDigitHeight - kDigitSpace, left + kDigitWidth,
+ kDigitHeight);
}
}();
@@ -69,7 +87,7 @@
canvas.drawRect(rect, paint);
}
-void RefreshRateOverlay::SevenSegmentDrawer::drawDigit(int digit, int left, SkColor& color,
+void RefreshRateOverlay::SevenSegmentDrawer::drawDigit(int digit, int left, SkColor color,
SkCanvas& canvas) {
if (digit < 0 || digit > 9) return;
@@ -94,37 +112,45 @@
drawSegment(Segment::Bottom, left, color, canvas);
}
-std::vector<sp<GraphicBuffer>> RefreshRateOverlay::SevenSegmentDrawer::draw(
- int number, SkColor& color, ui::Transform::RotationFlags rotation, bool showSpinner) {
+auto RefreshRateOverlay::SevenSegmentDrawer::draw(int number, SkColor color,
+ ui::Transform::RotationFlags rotation,
+ bool showSpinner) -> Buffers {
if (number < 0 || number > 1000) return {};
const auto hundreds = number / 100;
const auto tens = (number / 10) % 10;
const auto ones = number % 10;
- std::vector<sp<GraphicBuffer>> buffers;
- const auto loopCount = showSpinner ? 6 : 1;
- for (int i = 0; i < loopCount; i++) {
+ const size_t loopCount = showSpinner ? 6 : 1;
+
+ Buffers buffers;
+ buffers.reserve(loopCount);
+
+ for (size_t i = 0; i < loopCount; i++) {
// Pre-rotate the buffer before it reaches SurfaceFlinger.
SkMatrix canvasTransform = SkMatrix();
- auto [bufferWidth, bufferHeight] = [&] {
+ const auto [bufferWidth, bufferHeight] = [&]() -> std::pair<int, int> {
switch (rotation) {
case ui::Transform::ROT_90:
- canvasTransform.setTranslate(BUFFER_HEIGHT, 0);
- canvasTransform.preRotate(90);
- return std::make_tuple(BUFFER_HEIGHT, BUFFER_WIDTH);
+ canvasTransform.setTranslate(kBufferHeight, 0);
+ canvasTransform.preRotate(90.f);
+ return {kBufferHeight, kBufferWidth};
case ui::Transform::ROT_270:
- canvasTransform.setRotate(270, BUFFER_WIDTH / 2.0, BUFFER_WIDTH / 2.0);
- return std::make_tuple(BUFFER_HEIGHT, BUFFER_WIDTH);
+ canvasTransform.setRotate(270.f, kBufferWidth / 2.f, kBufferWidth / 2.f);
+ return {kBufferHeight, kBufferWidth};
default:
- return std::make_tuple(BUFFER_WIDTH, BUFFER_HEIGHT);
+ return {kBufferWidth, kBufferHeight};
}
}();
+
sp<GraphicBuffer> buffer =
- new GraphicBuffer(bufferWidth, bufferHeight, HAL_PIXEL_FORMAT_RGBA_8888, 1,
+ new GraphicBuffer(static_cast<uint32_t>(bufferWidth),
+ static_cast<uint32_t>(bufferHeight), HAL_PIXEL_FORMAT_RGBA_8888,
+ 1,
GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER |
GRALLOC_USAGE_HW_TEXTURE,
"RefreshRateOverlayBuffer");
+
const status_t bufferStatus = buffer->initCheck();
LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "RefreshRateOverlay: Buffer failed to allocate: %d",
bufferStatus);
@@ -137,15 +163,15 @@
if (hundreds != 0) {
drawDigit(hundreds, left, color, *canvas);
}
- left += DIGIT_WIDTH + DIGIT_SPACE;
+ left += kDigitWidth + kDigitSpace;
if (tens != 0) {
drawDigit(tens, left, color, *canvas);
}
- left += DIGIT_WIDTH + DIGIT_SPACE;
+ left += kDigitWidth + kDigitSpace;
drawDigit(ones, left, color, *canvas);
- left += DIGIT_WIDTH + DIGIT_SPACE;
+ left += kDigitWidth + kDigitSpace;
if (showSpinner) {
switch (i) {
@@ -172,51 +198,43 @@
void* pixels = nullptr;
buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&pixels));
+
const SkImageInfo& imageInfo = surface->imageInfo();
- size_t dstRowBytes = buffer->getStride() * imageInfo.bytesPerPixel();
+ const size_t dstRowBytes =
+ buffer->getStride() * static_cast<size_t>(imageInfo.bytesPerPixel());
+
canvas->readPixels(imageInfo, pixels, dstRowBytes, 0, 0);
buffer->unlock();
- buffers.emplace_back(buffer);
+ buffers.push_back(std::move(buffer));
}
return buffers;
}
-RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger, uint32_t lowFps, uint32_t highFps,
- bool showSpinner)
- : mFlinger(flinger),
- mClient(new Client(&mFlinger)),
+RefreshRateOverlay::RefreshRateOverlay(FpsRange fpsRange, bool showSpinner)
+ : mFpsRange(fpsRange),
mShowSpinner(showSpinner),
- mLowFps(lowFps),
- mHighFps(highFps) {
- createLayer();
-}
-
-bool RefreshRateOverlay::createLayer() {
- mSurfaceControl =
- SurfaceComposerClient::getDefault()
- ->createSurface(String8("RefreshRateOverlay"), SevenSegmentDrawer::getWidth(),
- SevenSegmentDrawer::getHeight(), PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceBufferState);
-
+ mSurfaceControl(SurfaceComposerClient::getDefault()
+ ->createSurface(String8("RefreshRateOverlay"), kBufferWidth,
+ kBufferHeight, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceBufferState)) {
if (!mSurfaceControl) {
- ALOGE("failed to create buffer state layer");
- return false;
+ ALOGE("%s: Failed to create buffer state layer", __func__);
+ return;
}
- SurfaceComposerClient::Transaction()
- .setFrameRate(mSurfaceControl, 0.0f,
- static_cast<int8_t>(Layer::FrameRateCompatibility::NoVote),
- static_cast<int8_t>(scheduler::Seamlessness::OnlySeamless))
+ createTransaction(mSurfaceControl)
.setLayer(mSurfaceControl, INT32_MAX - 2)
.setTrustedOverlay(mSurfaceControl, true)
.apply();
-
- return true;
}
-const std::vector<sp<GraphicBuffer>>& RefreshRateOverlay::getOrCreateBuffers(uint32_t fps) {
- ui::Transform::RotationFlags transformHint =
+auto RefreshRateOverlay::getOrCreateBuffers(Fps fps) -> const Buffers& {
+ static const Buffers kNoBuffers;
+ if (!mSurfaceControl) return kNoBuffers;
+
+ const auto transformHint =
static_cast<ui::Transform::RotationFlags>(mSurfaceControl->getTransformHint());
+
// Tell SurfaceFlinger about the pre-rotation on the buffer.
const auto transform = [&] {
switch (transformHint) {
@@ -229,74 +247,72 @@
}
}();
- SurfaceComposerClient::Transaction t;
- t.setTransform(mSurfaceControl, transform);
- t.apply();
+ createTransaction(mSurfaceControl).setTransform(mSurfaceControl, transform).apply();
- if (mBufferCache.find(transformHint) == mBufferCache.end() ||
- mBufferCache.at(transformHint).find(fps) == mBufferCache.at(transformHint).end()) {
- // Ensure the range is > 0, so we don't divide by 0.
- const auto rangeLength = std::max(1u, mHighFps - mLowFps);
- // Clip values outside the range [mLowFps, mHighFps]. The current fps may be outside
- // of this range if the display has changed its set of supported refresh rates.
- fps = std::max(fps, mLowFps);
- fps = std::min(fps, mHighFps);
- const auto fpsScale = static_cast<float>(fps - mLowFps) / rangeLength;
- SkColor4f colorBase = SkColor4f::FromColor(HIGH_FPS_COLOR) * fpsScale;
- SkColor4f lowFpsColor = SkColor4f::FromColor(LOW_FPS_COLOR) * (1 - fpsScale);
- colorBase.fR = colorBase.fR + lowFpsColor.fR;
- colorBase.fG = colorBase.fG + lowFpsColor.fG;
- colorBase.fB = colorBase.fB + lowFpsColor.fB;
- colorBase.fA = ALPHA;
- SkColor color = colorBase.toSkColor();
- auto buffers = SevenSegmentDrawer::draw(fps, color, transformHint, mShowSpinner);
- mBufferCache[transformHint].emplace(fps, buffers);
+ BufferCache::const_iterator it = mBufferCache.find({fps.getIntValue(), transformHint});
+ if (it == mBufferCache.end()) {
+ const int minFps = mFpsRange.min.getIntValue();
+ const int maxFps = mFpsRange.max.getIntValue();
+
+ // Clamp to the range. The current fps may be outside of this range if the display has
+ // changed its set of supported refresh rates.
+ const int intFps = std::clamp(fps.getIntValue(), minFps, maxFps);
+
+ // Ensure non-zero range to avoid division by zero.
+ const float fpsScale = static_cast<float>(intFps - minFps) / std::max(1, maxFps - minFps);
+
+ constexpr SkColor kMinFpsColor = SK_ColorRED;
+ constexpr SkColor kMaxFpsColor = SK_ColorGREEN;
+ constexpr float kAlpha = 0.8f;
+
+ SkColor4f colorBase = SkColor4f::FromColor(kMaxFpsColor) * fpsScale;
+ const SkColor4f minFpsColor = SkColor4f::FromColor(kMinFpsColor) * (1 - fpsScale);
+
+ colorBase.fR = colorBase.fR + minFpsColor.fR;
+ colorBase.fG = colorBase.fG + minFpsColor.fG;
+ colorBase.fB = colorBase.fB + minFpsColor.fB;
+ colorBase.fA = kAlpha;
+
+ const SkColor color = colorBase.toSkColor();
+
+ auto buffers = SevenSegmentDrawer::draw(intFps, color, transformHint, mShowSpinner);
+ it = mBufferCache.try_emplace({intFps, transformHint}, std::move(buffers)).first;
}
- return mBufferCache[transformHint][fps];
+ return it->second;
}
void RefreshRateOverlay::setViewport(ui::Size viewport) {
constexpr int32_t kMaxWidth = 1000;
- const auto width = std::min(kMaxWidth, std::min(viewport.width, viewport.height));
+ const auto width = std::min({kMaxWidth, viewport.width, viewport.height});
const auto height = 2 * width;
Rect frame((3 * width) >> 4, height >> 5);
frame.offsetBy(width >> 5, height >> 4);
- SurfaceComposerClient::Transaction t;
- t.setMatrix(mSurfaceControl,
- frame.getWidth() / static_cast<float>(SevenSegmentDrawer::getWidth()), 0, 0,
- frame.getHeight() / static_cast<float>(SevenSegmentDrawer::getHeight()));
- t.setPosition(mSurfaceControl, frame.left, frame.top);
- t.apply();
+ createTransaction(mSurfaceControl)
+ .setMatrix(mSurfaceControl, frame.getWidth() / static_cast<float>(kBufferWidth), 0, 0,
+ frame.getHeight() / static_cast<float>(kBufferHeight))
+ .setPosition(mSurfaceControl, frame.left, frame.top)
+ .apply();
}
void RefreshRateOverlay::setLayerStack(ui::LayerStack stack) {
- SurfaceComposerClient::Transaction t;
- t.setLayerStack(mSurfaceControl, stack);
- t.apply();
+ createTransaction(mSurfaceControl).setLayerStack(mSurfaceControl, stack).apply();
}
void RefreshRateOverlay::changeRefreshRate(Fps fps) {
- mCurrentFps = fps.getIntValue();
- auto buffer = getOrCreateBuffers(*mCurrentFps)[mFrame];
- SurfaceComposerClient::Transaction t;
- t.setBuffer(mSurfaceControl, buffer);
- t.apply();
+ mCurrentFps = fps;
+ const auto buffer = getOrCreateBuffers(fps)[mFrame];
+ createTransaction(mSurfaceControl).setBuffer(mSurfaceControl, buffer).apply();
}
void RefreshRateOverlay::animate() {
- if (!mCurrentFps.has_value()) return;
+ if (!mShowSpinner || !mCurrentFps) return;
const auto& buffers = getOrCreateBuffers(*mCurrentFps);
mFrame = (mFrame + 1) % buffers.size();
- auto buffer = buffers[mFrame];
- SurfaceComposerClient::Transaction t;
- t.setBuffer(mSurfaceControl, buffer);
- t.apply();
+ const auto buffer = buffers[mFrame];
+ createTransaction(mSurfaceControl).setBuffer(mSurfaceControl, buffer).apply();
}
} // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h
index 381df37..a465a36 100644
--- a/services/surfaceflinger/RefreshRateOverlay.h
+++ b/services/surfaceflinger/RefreshRateOverlay.h
@@ -16,32 +16,27 @@
#pragma once
-#include <SkCanvas.h>
#include <SkColor.h>
-#include <unordered_map>
+#include <vector>
-#include <math/vec4.h>
-#include <renderengine/RenderEngine.h>
+#include <ftl/small_map.h>
#include <ui/LayerStack.h>
-#include <ui/Rect.h>
#include <ui/Size.h>
+#include <ui/Transform.h>
#include <utils/StrongPointer.h>
#include <scheduler/Fps.h>
+class SkCanvas;
+
namespace android {
-class Client;
class GraphicBuffer;
-class IBinder;
-class IGraphicBufferProducer;
-class Layer;
-class SurfaceFlinger;
class SurfaceControl;
class RefreshRateOverlay {
public:
- RefreshRateOverlay(SurfaceFlinger&, uint32_t lowFps, uint32_t highFps, bool showSpinner);
+ RefreshRateOverlay(FpsRange, bool showSpinner);
void setLayerStack(ui::LayerStack);
void setViewport(ui::Size);
@@ -49,52 +44,38 @@
void animate();
private:
+ using Buffers = std::vector<sp<GraphicBuffer>>;
+
class SevenSegmentDrawer {
public:
- static std::vector<sp<GraphicBuffer>> draw(int number, SkColor& color,
- ui::Transform::RotationFlags, bool showSpinner);
- static uint32_t getHeight() { return BUFFER_HEIGHT; }
- static uint32_t getWidth() { return BUFFER_WIDTH; }
+ static Buffers draw(int number, SkColor, ui::Transform::RotationFlags, bool showSpinner);
private:
enum class Segment { Upper, UpperLeft, UpperRight, Middle, LowerLeft, LowerRight, Bottom };
- static void drawSegment(Segment segment, int left, SkColor& color, SkCanvas& canvas);
- static void drawDigit(int digit, int left, SkColor& color, SkCanvas& canvas);
-
- static constexpr uint32_t DIGIT_HEIGHT = 100;
- static constexpr uint32_t DIGIT_WIDTH = 64;
- static constexpr uint32_t DIGIT_SPACE = 16;
- static constexpr uint32_t BUFFER_HEIGHT = DIGIT_HEIGHT;
- static constexpr uint32_t BUFFER_WIDTH =
- 4 * DIGIT_WIDTH + 3 * DIGIT_SPACE; // Digit|Space|Digit|Space|Digit|Space|Spinner
+ static void drawSegment(Segment, int left, SkColor, SkCanvas&);
+ static void drawDigit(int digit, int left, SkColor, SkCanvas&);
};
- bool createLayer();
+ const Buffers& getOrCreateBuffers(Fps);
- const std::vector<sp<GraphicBuffer>>& getOrCreateBuffers(uint32_t fps);
+ struct Key {
+ int fps;
+ ui::Transform::RotationFlags flags;
- SurfaceFlinger& mFlinger;
- const sp<Client> mClient;
- sp<IBinder> mIBinder;
- sp<IGraphicBufferProducer> mGbp;
+ bool operator==(Key other) const { return fps == other.fps && flags == other.flags; }
+ };
- std::unordered_map<ui::Transform::RotationFlags,
- std::unordered_map<int, std::vector<sp<GraphicBuffer>>>>
- mBufferCache;
- std::optional<int> mCurrentFps;
- int mFrame = 0;
- static constexpr float ALPHA = 0.8f;
- const SkColor LOW_FPS_COLOR = SK_ColorRED;
- const SkColor HIGH_FPS_COLOR = SK_ColorGREEN;
+ using BufferCache = ftl::SmallMap<Key, Buffers, 9>;
+ BufferCache mBufferCache;
+ std::optional<Fps> mCurrentFps;
+ size_t mFrame = 0;
+
+ const FpsRange mFpsRange; // For color interpolation.
const bool mShowSpinner;
- // Interpolate the colors between these values.
- const uint32_t mLowFps;
- const uint32_t mHighFps;
-
- sp<SurfaceControl> mSurfaceControl;
+ const sp<SurfaceControl> mSurfaceControl;
};
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 5ba8a1b..cbea77e 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -346,6 +346,12 @@
VsyncEventData EventThread::getLatestVsyncEventData(
const sp<EventThreadConnection>& connection) const {
+ // Resync so that the vsync is accurate with hardware. getLatestVsyncEventData is an alternate
+ // way to get vsync data (instead of posting callbacks to Choreographer).
+ if (connection->resyncCallback) {
+ connection->resyncCallback();
+ }
+
VsyncEventData vsyncEventData;
nsecs_t frameInterval = mGetVsyncPeriodFunction(connection->mOwnerUid);
vsyncEventData.frameInterval = frameInterval;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 3226f22..ca83496 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -133,9 +133,9 @@
} // namespace
std::string RefreshRateConfigs::Policy::toString() const {
- return base::StringPrintf("default mode ID: %d, allowGroupSwitching = %d"
- ", primary range: %s, app request range: %s",
- defaultMode.value(), allowGroupSwitching,
+ return base::StringPrintf("{defaultModeId=%d, allowGroupSwitching=%s"
+ ", primaryRange=%s, appRequestRange=%s}",
+ defaultMode.value(), allowGroupSwitching ? "true" : "false",
to_string(primaryRange).c_str(), to_string(appRequestRange).c_str());
}
@@ -922,41 +922,46 @@
}
void RefreshRateConfigs::dump(std::string& result) const {
+ using namespace std::string_literals;
+
std::lock_guard lock(mLock);
- base::StringAppendF(&result, "DesiredDisplayModeSpecs (DisplayManager): %s\n\n",
- mDisplayManagerPolicy.toString().c_str());
- scheduler::RefreshRateConfigs::Policy currentPolicy = *getCurrentPolicyLocked();
- if (mOverridePolicy && currentPolicy != mDisplayManagerPolicy) {
- base::StringAppendF(&result, "DesiredDisplayModeSpecs (Override): %s\n\n",
- currentPolicy.toString().c_str());
- }
- base::StringAppendF(&result, "Active mode: %s\n", to_string(*mActiveModeIt->second).c_str());
+ const auto activeModeId = mActiveModeIt->first;
+ result += " activeModeId="s;
+ result += std::to_string(activeModeId.value());
- result.append("Display modes:\n");
+ result += "\n displayModes=\n"s;
for (const auto& [id, mode] : mDisplayModes) {
- result.push_back('\t');
- result.append(to_string(*mode));
- result.push_back('\n');
+ result += " "s;
+ result += to_string(*mode);
+ result += '\n';
}
- base::StringAppendF(&result, "Supports Frame Rate Override By Content: %s\n",
- mSupportsFrameRateOverrideByContent ? "yes" : "no");
+ base::StringAppendF(&result, " displayManagerPolicy=%s\n",
+ mDisplayManagerPolicy.toString().c_str());
- result.append("Idle timer: ");
- if (const auto controller = mConfig.kernelIdleTimerController) {
- base::StringAppendF(&result, "(kernel via %s) ", ftl::enum_string(*controller).c_str());
- } else {
- result.append("(platform) ");
+ if (const Policy& currentPolicy = *getCurrentPolicyLocked();
+ mOverridePolicy && currentPolicy != mDisplayManagerPolicy) {
+ base::StringAppendF(&result, " overridePolicy=%s\n", currentPolicy.toString().c_str());
}
+ base::StringAppendF(&result, " supportsFrameRateOverrideByContent=%s\n",
+ mSupportsFrameRateOverrideByContent ? "true" : "false");
+
+ result += " idleTimer="s;
if (mIdleTimer) {
- result.append(mIdleTimer->dump());
+ result += mIdleTimer->dump();
} else {
- result.append("off");
+ result += "off"s;
}
- result.append("\n\n");
+ if (const auto controller = mConfig.kernelIdleTimerController) {
+ base::StringAppendF(&result, " (kernel via %s)", ftl::enum_string(*controller).c_str());
+ } else {
+ result += " (platform)"s;
+ }
+
+ result += '\n';
}
std::chrono::milliseconds RefreshRateConfigs::getIdleTimerTimeout() {
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/Features.h b/services/surfaceflinger/Scheduler/include/scheduler/Features.h
index 0e96678..b3a6a60 100644
--- a/services/surfaceflinger/Scheduler/include/scheduler/Features.h
+++ b/services/surfaceflinger/Scheduler/include/scheduler/Features.h
@@ -16,10 +16,10 @@
#pragma once
-#include <ftl/Flags.h>
-
#include <cstdint>
+#include <ftl/flags.h>
+
namespace android::scheduler {
enum class Feature : std::uint8_t {
@@ -29,6 +29,6 @@
kTracePredictedVsync = 0b1000,
};
-using FeatureFlags = Flags<Feature>;
+using FeatureFlags = ftl::Flags<Feature>;
} // namespace android::scheduler
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 9f5a7df..d39176b 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -24,7 +24,10 @@
#include "SurfaceFlinger.h"
+#include <android-base/parseint.h>
#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <android/configuration.h>
#include <android/gui/IDisplayEventConnection.h>
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
@@ -49,6 +52,7 @@
#include <configstore/Utils.h>
#include <cutils/compiler.h>
#include <cutils/properties.h>
+#include <ftl/fake_guard.h>
#include <ftl/future.h>
#include <ftl/small_map.h>
#include <gui/BufferQueue.h>
@@ -91,6 +95,7 @@
#include <cmath>
#include <cstdint>
#include <functional>
+#include <memory>
#include <mutex>
#include <optional>
#include <type_traits>
@@ -109,6 +114,7 @@
#include "DisplayHardware/FramebufferSurface.h"
#include "DisplayHardware/HWComposer.h"
#include "DisplayHardware/Hal.h"
+#include "DisplayHardware/PowerAdvisor.h"
#include "DisplayHardware/VirtualDisplaySurface.h"
#include "DisplayRenderArea.h"
#include "EffectLayer.h"
@@ -123,6 +129,7 @@
#include "LayerRenderArea.h"
#include "LayerVector.h"
#include "MonitoredProducer.h"
+#include "MutexUtils.h"
#include "NativeWindowSurface.h"
#include "RefreshRateOverlay.h"
#include "RegionSamplingThread.h"
@@ -138,49 +145,29 @@
#include "TimeStats/TimeStats.h"
#include "TunnelModeEnabledReporter.h"
#include "WindowInfosListenerInvoker.h"
-#include "android-base/parseint.h"
-#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)
-
-// Note: The parentheses around `expr` are needed to deduce an lvalue or rvalue reference.
-#define ON_MAIN_THREAD(expr) \
- [&]() -> decltype(auto) { \
- LOG_FATAL_IF(std::this_thread::get_id() != mMainThreadId); \
- UnnecessaryLock lock(mStateLock); \
- return (expr); \
- }()
-
-#define MAIN_THREAD_GUARD(expr) \
- [&]() -> decltype(auto) { \
- LOG_FATAL_IF(std::this_thread::get_id() != mMainThreadId); \
- MainThreadScopedGuard lock(SF_MAIN_THREAD); \
- return (expr); \
- }()
+#include <aidl/android/hardware/graphics/composer3/RenderIntent.h>
#undef NO_THREAD_SAFETY_ANALYSIS
#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;
-using KernelIdleTimerController =
- ::android::scheduler::RefreshRateConfigs::KernelIdleTimerController;
+ _Pragma("GCC error \"Prefer <ftl/fake_guard.h> or MutexUtils.h helpers.\"")
namespace android {
using namespace std::string_literals;
-using namespace android::hardware::configstore;
-using namespace android::hardware::configstore::V1_0;
-using namespace android::sysprop;
+using namespace hardware::configstore;
+using namespace hardware::configstore::V1_0;
+using namespace sysprop;
-using android::hardware::power::Boost;
+using aidl::android::hardware::graphics::common::DisplayDecorationSupport;
+using aidl::android::hardware::graphics::composer3::Capability;
+using aidl::android::hardware::graphics::composer3::DisplayCapability;
+using CompositionStrategyPredictionState = android::compositionengine::impl::
+ OutputCompositionState::CompositionStrategyPredictionState;
+
using base::StringAppendF;
using gui::DisplayInfo;
using gui::IDisplayEventConnection;
@@ -191,6 +178,8 @@
using ui::DisplayPrimaries;
using ui::RenderIntent;
+using KernelIdleTimerController = scheduler::RefreshRateConfigs::KernelIdleTimerController;
+
namespace hal = android::hardware::graphics::composer::hal;
namespace {
@@ -222,38 +211,6 @@
#pragma clang diagnostic pop
-template <typename Mutex>
-struct SCOPED_CAPABILITY ConditionalLockGuard {
- ConditionalLockGuard(Mutex& mutex, bool lock) ACQUIRE(mutex) : mutex(mutex), lock(lock) {
- if (lock) mutex.lock();
- }
-
- ~ConditionalLockGuard() RELEASE() {
- if (lock) mutex.unlock();
- }
-
- Mutex& mutex;
- const bool lock;
-};
-
-using ConditionalLock = ConditionalLockGuard<Mutex>;
-
-struct SCOPED_CAPABILITY TimedLock {
- TimedLock(Mutex& mutex, nsecs_t timeout, const char* whence) ACQUIRE(mutex)
- : mutex(mutex), status(mutex.timedLock(timeout)) {
- ALOGE_IF(!locked(), "%s timed out locking: %s (%d)", whence, strerror(-status), status);
- }
-
- ~TimedLock() RELEASE() {
- if (locked()) mutex.unlock();
- }
-
- bool locked() const { return status == NO_ERROR; }
-
- Mutex& mutex;
- const status_t status;
-};
-
// TODO(b/141333600): Consolidate with DisplayMode::Builder::getDefaultDensity.
constexpr float FALLBACK_DENSITY = ACONFIGURATION_DENSITY_TV;
@@ -373,7 +330,7 @@
mTunnelModeEnabledReporter(new TunnelModeEnabledReporter()),
mInternalDisplayDensity(getDensityFromProperty("ro.sf.lcd_density", true)),
mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)),
- mPowerAdvisor(*this),
+ mPowerAdvisor(std::make_unique<Hwc2::impl::PowerAdvisor>(*this)),
mWindowInfosListenerInvoker(sp<WindowInfosListenerInvoker>::make(*this)) {
ALOGI("Using HWComposer service: %s", mHwcServiceName.c_str());
}
@@ -459,6 +416,9 @@
property_get("debug.sf.disable_client_composition_cache", value, "0");
mDisableClientCompositionCache = atoi(value);
+ property_get("debug.sf.predict_hwc_composition_strategy", value, "1");
+ mPredictCompositionStrategy = atoi(value);
+
// We should be reading 'persist.sys.sf.color_saturation' here
// but since /data may be encrypted, we need to wait until after vold
// comes online to attempt to read the property. The property is
@@ -623,14 +583,8 @@
std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIdsLocked() const {
std::vector<PhysicalDisplayId> displayIds;
displayIds.reserve(mPhysicalDisplayTokens.size());
- const auto defaultDisplayId = [this]() REQUIRES(mStateLock) {
- if (const auto display = getDefaultDisplayDeviceLocked()) {
- return display->getPhysicalId();
- }
- // fallback to the internal display id if the active display is unknown
- return getInternalDisplayIdLocked();
- }();
+ const auto defaultDisplayId = getDefaultDisplayDeviceLocked()->getPhysicalId();
displayIds.push_back(defaultDisplayId);
for (const auto& [id, token] : mPhysicalDisplayTokens) {
@@ -644,7 +598,7 @@
status_t SurfaceFlinger::getPrimaryPhysicalDisplayId(PhysicalDisplayId* id) const {
Mutex::Autolock lock(mStateLock);
- *id = getInternalDisplayIdLocked();
+ *id = getPrimaryDisplayIdLocked();
return NO_ERROR;
}
@@ -720,22 +674,28 @@
}
readPersistentProperties();
- mPowerAdvisor.onBootFinished();
- mPowerAdvisor.enablePowerHint(mFlagManager.use_adpf_cpu_hint());
- if (mPowerAdvisor.usePowerHintSession()) {
+ mPowerAdvisor->onBootFinished();
+ const bool powerHintEnabled = mFlagManager.use_adpf_cpu_hint();
+ mPowerAdvisor->enablePowerHint(powerHintEnabled);
+ const bool powerHintUsed = mPowerAdvisor->usePowerHintSession();
+ ALOGD("Power hint is %s",
+ powerHintUsed ? "supported" : (powerHintEnabled ? "unsupported" : "disabled"));
+ if (powerHintUsed) {
std::optional<pid_t> renderEngineTid = getRenderEngine().getRenderEngineTid();
std::vector<int32_t> tidList;
tidList.emplace_back(gettid());
if (renderEngineTid.has_value()) {
tidList.emplace_back(*renderEngineTid);
}
- mPowerAdvisor.startPowerHintSession(tidList);
+ if (!mPowerAdvisor->startPowerHintSession(tidList)) {
+ ALOGW("Cannot start power hint session");
+ }
}
mBootStage = BootStage::FINISHED;
if (property_get_bool("sf.debug.show_refresh_rate_overlay", false)) {
- ON_MAIN_THREAD(enableRefreshRateOverlay(true));
+ FTL_FAKE_GUARD(mStateLock, enableRefreshRateOverlay(true));
}
}));
}
@@ -853,7 +813,7 @@
// set initial conditions (e.g. unblank default device)
initializeDisplays();
- mPowerAdvisor.init();
+ mPowerAdvisor->init();
char primeShaderCache[PROPERTY_VALUE_MAX];
property_get("service.sf.prime_shader_cache", primeShaderCache, "1");
@@ -936,8 +896,9 @@
FrameEvent::DEQUEUE_READY,
FrameEvent::RELEASE,
};
- ConditionalLock _l(mStateLock,
- std::this_thread::get_id() != mMainThreadId);
+
+ ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
+
if (!getHwComposer().hasCapability(Capability::PRESENT_FENCE_IS_NOT_RELIABLE)) {
outSupported->push_back(FrameEvent::DISPLAY_PRESENT);
}
@@ -1040,13 +1001,8 @@
outMode.resolution = ui::Size(width, height);
- if (mEmulatedDisplayDensity) {
- outMode.xDpi = mEmulatedDisplayDensity;
- outMode.yDpi = mEmulatedDisplayDensity;
- } else {
- outMode.xDpi = xDpi;
- outMode.yDpi = yDpi;
- }
+ outMode.xDpi = xDpi;
+ outMode.yDpi = yDpi;
const nsecs_t period = mode->getVsyncPeriod();
outMode.refreshRate = Fps::fromPeriodNsecs(period).getValue();
@@ -1142,7 +1098,7 @@
}
auto future = mScheduler->schedule([=]() -> status_t {
- const auto display = ON_MAIN_THREAD(getDisplayDeviceLocked(displayToken));
+ const auto display = FTL_FAKE_GUARD(mStateLock, getDisplayDeviceLocked(displayToken));
if (!display) {
ALOGE("Attempt to set allowed display modes for invalid display token %p",
displayToken.get());
@@ -1183,7 +1139,9 @@
return;
}
- const auto upcomingModeInfo = MAIN_THREAD_GUARD(display->getUpcomingActiveMode());
+ const auto upcomingModeInfo =
+ FTL_FAKE_GUARD(kMainThreadContext, display->getUpcomingActiveMode());
+
if (!upcomingModeInfo.mode) {
// There is no pending mode change. This can happen if the active
// display changed and the mode change happened on a different display.
@@ -1202,9 +1160,8 @@
return;
}
- // We just created this display so we can call even if we are not on
- // the main thread
- MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD);
+ // We just created this display so we can call even if we are not on the main thread.
+ ftl::FakeGuard guard(kMainThreadContext);
display->setActiveMode(upcomingModeInfo.mode->getId());
const Fps refreshRate = upcomingModeInfo.mode->getFps();
@@ -1289,8 +1246,10 @@
constraints.seamlessRequired = false;
hal::VsyncPeriodChangeTimeline outTimeline;
- const auto status = MAIN_THREAD_GUARD(
- display->initiateModeChange(*desiredActiveMode, constraints, &outTimeline));
+ const auto status = FTL_FAKE_GUARD(kMainThreadContext,
+ display->initiateModeChange(*desiredActiveMode,
+ constraints, &outTimeline));
+
if (status != NO_ERROR) {
// initiateModeChange may fail if a hotplug event is just about
// to be sent. We just log the error in this case.
@@ -1323,12 +1282,13 @@
}
void SurfaceFlinger::disableExpensiveRendering() {
- auto future = mScheduler->schedule([=]() MAIN_THREAD {
- ATRACE_CALL();
- if (mPowerAdvisor.isUsingExpensiveRendering()) {
+ const char* const whence = __func__;
+ auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
+ ATRACE_NAME(whence);
+ if (mPowerAdvisor->isUsingExpensiveRendering()) {
for (const auto& [_, display] : mDisplays) {
constexpr bool kDisable = false;
- mPowerAdvisor.setExpensiveRenderingExpected(display->getId(), kDisable);
+ mPowerAdvisor->setExpensiveRenderingExpected(display->getId(), kDisable);
}
}
});
@@ -1353,17 +1313,25 @@
}
status_t SurfaceFlinger::getDisplayNativePrimaries(const sp<IBinder>& displayToken,
- ui::DisplayPrimaries &primaries) {
+ ui::DisplayPrimaries& primaries) {
if (!displayToken) {
return BAD_VALUE;
}
- // Currently we only support this API for a single internal display.
- if (getInternalDisplayToken() != displayToken) {
+ Mutex::Autolock lock(mStateLock);
+
+ const auto display = getDisplayDeviceLocked(displayToken);
+ if (!display) {
return NAME_NOT_FOUND;
}
- memcpy(&primaries, &mInternalDisplayPrimaries, sizeof(ui::DisplayPrimaries));
+ const auto connectionType = display->getConnectionType();
+ if (connectionType != ui::DisplayConnectionType::Internal) {
+ return INVALID_OPERATION;
+ }
+
+ // TODO(b/229846990): For now, assume that all internal displays have the same primaries.
+ primaries = mInternalDisplayPrimaries;
return NO_ERROR;
}
@@ -1372,7 +1340,7 @@
return BAD_VALUE;
}
- auto future = mScheduler->schedule([=]() MAIN_THREAD -> status_t {
+ auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) -> status_t {
const auto display = getDisplayDeviceLocked(displayToken);
if (!display) {
ALOGE("Attempt to set active color mode %s (%d) for invalid display token %p",
@@ -1407,17 +1375,17 @@
}
status_t SurfaceFlinger::getBootDisplayModeSupport(bool* outSupport) const {
- auto future = mScheduler->schedule([=]() MAIN_THREAD mutable -> status_t {
- *outSupport = getHwComposer().hasCapability(Capability::BOOT_DISPLAY_CONFIG);
- return NO_ERROR;
- });
- return future.get();
+ auto future = mScheduler->schedule(
+ [this] { return getHwComposer().hasCapability(Capability::BOOT_DISPLAY_CONFIG); });
+
+ *outSupport = future.get();
+ return NO_ERROR;
}
status_t SurfaceFlinger::setBootDisplayMode(const sp<IBinder>& displayToken,
ui::DisplayModeId modeId) {
const char* const whence = __func__;
- auto future = mScheduler->schedule([=]() MAIN_THREAD -> status_t {
+ auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) -> status_t {
const auto display = getDisplayDeviceLocked(displayToken);
if (!display) {
ALOGE("%s: Invalid display token %p", whence, displayToken.get());
@@ -1444,7 +1412,7 @@
status_t SurfaceFlinger::clearBootDisplayMode(const sp<IBinder>& displayToken) {
const char* const whence = __func__;
- auto future = mScheduler->schedule([=]() MAIN_THREAD -> status_t {
+ auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) -> status_t {
if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
return getHwComposer().clearBootDisplayMode(*displayId);
} else {
@@ -1457,7 +1425,7 @@
void SurfaceFlinger::setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on) {
const char* const whence = __func__;
- static_cast<void>(mScheduler->schedule([=]() MAIN_THREAD {
+ static_cast<void>(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
getHwComposer().setAutoLowLatencyMode(*displayId, on);
} else {
@@ -1468,7 +1436,7 @@
void SurfaceFlinger::setGameContentType(const sp<IBinder>& displayToken, bool on) {
const char* const whence = __func__;
- static_cast<void>(mScheduler->schedule([=]() MAIN_THREAD {
+ static_cast<void>(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
const auto type = on ? hal::ContentType::GAME : hal::ContentType::NONE;
getHwComposer().setContentType(*displayId, type);
@@ -1533,7 +1501,7 @@
bool enable, uint8_t componentMask,
uint64_t maxFrames) {
const char* const whence = __func__;
- auto future = mScheduler->schedule([=]() MAIN_THREAD -> status_t {
+ auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) -> status_t {
if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
return getHwComposer().setDisplayContentSamplingEnabled(*displayId, enable,
componentMask, maxFrames);
@@ -1610,7 +1578,7 @@
status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) {
outLayers->clear();
auto future = mScheduler->schedule([=] {
- const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
+ const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked());
mDrawingState.traverseInZOrder([&](Layer* layer) {
outLayers->push_back(layer->getLayerDebugInfo(display.get()));
});
@@ -1722,7 +1690,7 @@
}
const char* const whence = __func__;
- return ftl::chain(mScheduler->schedule([=]() MAIN_THREAD {
+ return ftl::chain(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
if (const auto display = getDisplayDeviceLocked(displayToken)) {
const bool supportsDisplayBrightnessCommand =
getHwComposer().getComposer()->isSupported(
@@ -1736,7 +1704,9 @@
compositionDisplay->editState().displayBrightnessNits;
compositionDisplay->setDisplayBrightness(brightness.sdrWhitePointNits,
brightness.displayBrightnessNits);
- MAIN_THREAD_GUARD(display->stageBrightness(brightness.displayBrightness));
+ FTL_FAKE_GUARD(kMainThreadContext,
+ display->stageBrightness(brightness.displayBrightness));
+
if (brightness.sdrWhitePointNits / brightness.displayBrightnessNits !=
currentDimmingRatio) {
scheduleComposite(FrameHint::kNone);
@@ -1748,6 +1718,7 @@
return getHwComposer()
.setDisplayBrightness(display->getPhysicalId(),
brightness.displayBrightness,
+ brightness.displayBrightnessNits,
Hwc2::Composer::DisplayBrightnessOptions{
.applyImmediately = true});
}
@@ -1806,6 +1777,7 @@
}
status_t SurfaceFlinger::notifyPowerBoost(int32_t boostId) {
+ using hardware::power::Boost;
Boost powerBoost = static_cast<Boost>(boostId);
if (powerBoost == Boost::INTERACTION) {
@@ -1847,7 +1819,7 @@
if (hint == FrameHint::kActive) {
mScheduler->resetIdleTimer();
}
- mPowerAdvisor.notifyDisplayUpdateImminent();
+ mPowerAdvisor->notifyDisplayUpdateImminent();
mScheduler->scheduleFrame();
}
@@ -1966,7 +1938,7 @@
ATRACE_CALL();
// On main thread to avoid race conditions with display power state.
- static_cast<void>(mScheduler->schedule([=]() MAIN_THREAD {
+ static_cast<void>(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
mHWCVsyncPendingState = enabled ? hal::Vsync::ENABLE : hal::Vsync::DISABLE;
if (const auto display = getDefaultDisplayDeviceLocked();
@@ -2014,10 +1986,10 @@
: stats.vsyncTime + stats.vsyncPeriod;
}
-bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime) {
- MainThreadScopedGuard mainThreadGuard(SF_MAIN_THREAD);
+bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime)
+ FTL_FAKE_GUARD(kMainThreadContext) {
// we set this once at the beginning of commit to ensure consistency throughout the whole frame
- mPowerHintSessionData.sessionEnabled = mPowerAdvisor.usePowerHintSession();
+ mPowerHintSessionData.sessionEnabled = mPowerAdvisor->usePowerHintSession();
if (mPowerHintSessionData.sessionEnabled) {
mPowerHintSessionData.commitStart = systemTime();
}
@@ -2036,8 +2008,8 @@
mScheduledPresentTime = expectedVsyncTime;
if (mPowerHintSessionData.sessionEnabled) {
- mPowerAdvisor.setTargetWorkDuration(mExpectedPresentTime -
- mPowerHintSessionData.commitStart);
+ mPowerAdvisor->setTargetWorkDuration(mExpectedPresentTime -
+ mPowerHintSessionData.commitStart);
}
const auto vsyncIn = [&] {
if (!ATRACE_ENABLED()) return 0.f;
@@ -2181,20 +2153,21 @@
mLayerTracing.notify(mVisibleRegionsDirty, frameTime);
}
- MAIN_THREAD_GUARD(persistDisplayBrightness(mustComposite));
+ persistDisplayBrightness(mustComposite);
return mustComposite && CC_LIKELY(mBootStage != BootStage::BOOTLOADER);
}
-void SurfaceFlinger::composite(nsecs_t frameTime, int64_t vsyncId) {
+void SurfaceFlinger::composite(nsecs_t frameTime, int64_t vsyncId)
+ FTL_FAKE_GUARD(kMainThreadContext) {
ATRACE_FORMAT("%s %" PRId64, __func__, vsyncId);
- MainThreadScopedGuard mainThreadGuard(SF_MAIN_THREAD);
+
if (mPowerHintSessionData.sessionEnabled) {
mPowerHintSessionData.compositeStart = systemTime();
}
compositionengine::CompositionRefreshArgs refreshArgs;
- const auto& displays = ON_MAIN_THREAD(mDisplays);
+ const auto& displays = FTL_FAKE_GUARD(mStateLock, mDisplays);
refreshArgs.outputs.reserve(displays.size());
for (const auto& [_, display] : displays) {
refreshArgs.outputs.push_back(display->getCompositionDisplay());
@@ -2261,24 +2234,24 @@
const bool prevFrameHadClientComposition = mHadClientComposition;
- mHadClientComposition = std::any_of(displays.cbegin(), displays.cend(), [](const auto& pair) {
- const auto& state = pair.second->getCompositionDisplay()->getState();
- return state.usesClientComposition && !state.reusedClientComposition;
- });
- mHadDeviceComposition = std::any_of(displays.cbegin(), displays.cend(), [](const auto& pair) {
- const auto& state = pair.second->getCompositionDisplay()->getState();
- return state.usesDeviceComposition;
- });
- mReusedClientComposition =
- std::any_of(displays.cbegin(), displays.cend(), [](const auto& pair) {
- const auto& state = pair.second->getCompositionDisplay()->getState();
- return state.reusedClientComposition;
- });
- // Only report a strategy change if we move in and out of client composition
- if (prevFrameHadClientComposition != mHadClientComposition) {
- mTimeStats->incrementCompositionStrategyChanges();
+ mHadClientComposition = mHadDeviceComposition = mReusedClientComposition = false;
+ TimeStats::ClientCompositionRecord clientCompositionRecord;
+ for (const auto& [_, display] : displays) {
+ const auto& state = display->getCompositionDisplay()->getState();
+ mHadClientComposition |= state.usesClientComposition && !state.reusedClientComposition;
+ mHadDeviceComposition |= state.usesDeviceComposition;
+ mReusedClientComposition |= state.reusedClientComposition;
+ clientCompositionRecord.predicted |=
+ (state.strategyPrediction != CompositionStrategyPredictionState::DISABLED);
+ clientCompositionRecord.predictionSucceeded |=
+ (state.strategyPrediction == CompositionStrategyPredictionState::SUCCESS);
}
+ clientCompositionRecord.hadClientComposition = mHadClientComposition;
+ clientCompositionRecord.reused = mReusedClientComposition;
+ clientCompositionRecord.changed = prevFrameHadClientComposition != mHadClientComposition;
+ mTimeStats->pushCompositionStrategyState(clientCompositionRecord);
+
// TODO: b/160583065 Enable skip validation when SF caches all client composition layers
const bool usedGpuComposition = mHadClientComposition || mReusedClientComposition;
modulateVsync(&VsyncModulator::onDisplayRefresh, usedGpuComposition);
@@ -2300,7 +2273,7 @@
if (mPowerHintSessionData.sessionEnabled) {
const nsecs_t flingerDuration =
(mPowerHintSessionData.presentEnd - mPowerHintSessionData.commitStart);
- mPowerAdvisor.sendActualWorkDuration(flingerDuration, mPowerHintSessionData.presentEnd);
+ mPowerAdvisor->sendActualWorkDuration(flingerDuration, mPowerHintSessionData.presentEnd);
}
}
@@ -2380,7 +2353,12 @@
}
bool SurfaceFlinger::isHdrLayer(Layer* layer) const {
- if (!isHdrDataspace(layer->getDataSpace())) {
+ // Treat all layers as non-HDR if:
+ // 1. They do not have a valid HDR dataspace. Currently we treat those as PQ or HLG. and
+ // 2. The layer is allowed to be dimmed. WindowManager may disable dimming in order to
+ // keep animations invoking SDR screenshots of HDR layers seamless. Treat such tagged
+ // layers as HDR so that DisplayManagerService does not try to change the screen brightness
+ if (!isHdrDataspace(layer->getDataSpace()) && layer->isDimmingEnabled()) {
return false;
}
if (mIgnoreHdrCameraLayers) {
@@ -2432,7 +2410,7 @@
ATRACE_CALL();
ALOGV("postComposition");
- const auto* display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()).get();
+ const auto* display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()).get();
getBE().mGlCompositionDoneTimeline.updateSignalTimes();
std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
@@ -2569,13 +2547,6 @@
}
mTimeStats->incrementTotalFrames();
- if (mHadClientComposition) {
- mTimeStats->incrementClientCompositionFrames();
- }
-
- if (mReusedClientComposition) {
- mTimeStats->incrementClientCompositionReusedFrames();
- }
mTimeStats->setPresentFenceGlobal(mPreviousPresentFences[0].fenceTime);
@@ -2632,44 +2603,37 @@
}
FloatRect SurfaceFlinger::getMaxDisplayBounds() {
- // Find the largest width and height among all the displays.
- int32_t maxDisplayWidth = 0;
- int32_t maxDisplayHeight = 0;
+ const ui::Size maxSize = [this] {
+ ftl::FakeGuard guard(mStateLock);
- // If there are no displays, set a valid display bounds so we can still compute a valid layer
- // bounds.
- if (ON_MAIN_THREAD(mDisplays.size()) == 0) {
- maxDisplayWidth = maxDisplayHeight = 5000;
- }
+ // The LayerTraceGenerator tool runs without displays.
+ if (mDisplays.empty()) return ui::Size{5000, 5000};
- for (const auto& pair : ON_MAIN_THREAD(mDisplays)) {
- const auto& displayDevice = pair.second;
- int32_t width = displayDevice->getWidth();
- int32_t height = displayDevice->getHeight();
- if (width > maxDisplayWidth) {
- maxDisplayWidth = width;
- }
- if (height > maxDisplayHeight) {
- maxDisplayHeight = height;
- }
- }
+ return std::accumulate(mDisplays.begin(), mDisplays.end(), ui::kEmptySize,
+ [](ui::Size size, const auto& pair) -> ui::Size {
+ const auto& display = pair.second;
+ return {std::max(size.getWidth(), display->getWidth()),
+ std::max(size.getHeight(), display->getHeight())};
+ });
+ }();
// Ignore display bounds for now since they will be computed later. Use a large Rect bound
// to ensure it's bigger than an actual display will be.
- FloatRect maxBounds = FloatRect(-maxDisplayWidth * 10, -maxDisplayHeight * 10,
- maxDisplayWidth * 10, maxDisplayHeight * 10);
- return maxBounds;
+ const float xMax = maxSize.getWidth() * 10.f;
+ const float yMax = maxSize.getHeight() * 10.f;
+
+ return {-xMax, -yMax, xMax, yMax};
}
void SurfaceFlinger::computeLayerBounds() {
- FloatRect maxBounds = getMaxDisplayBounds();
+ const FloatRect maxBounds = getMaxDisplayBounds();
for (const auto& layer : mDrawingState.layersSortedByZ) {
layer->computeBounds(maxBounds, ui::Transform(), 0.f /* shadowRadius */);
}
}
void SurfaceFlinger::postFrame() {
- const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
+ const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked());
if (display && getHwComposer().isConnected(display->getPhysicalId())) {
uint32_t flipCount = display->getPageFlipCount();
if (flipCount % LOG_FRAME_STATS_PERIOD == 0) {
@@ -2778,12 +2742,12 @@
}
const auto displayId = info->id;
- const auto it = mPhysicalDisplayTokens.find(displayId);
+ const auto token = mPhysicalDisplayTokens.get(displayId);
if (event.connection == hal::Connection::CONNECTED) {
auto [supportedModes, activeMode] = loadDisplayModes(displayId);
- if (it == mPhysicalDisplayTokens.end()) {
+ if (!token) {
ALOGV("Creating display %s", to_string(displayId).c_str());
DisplayDeviceState state;
@@ -2798,14 +2762,13 @@
sp<IBinder> token = new BBinder();
mCurrentState.displays.add(token, state);
- mPhysicalDisplayTokens.emplace(displayId, std::move(token));
+ mPhysicalDisplayTokens.try_emplace(displayId, std::move(token));
mInterceptor->saveDisplayCreation(state);
} else {
ALOGV("Recreating display %s", to_string(displayId).c_str());
- const auto token = it->second;
- auto& state = mCurrentState.displays.editValueFor(token);
- state.sequenceId = DisplayDeviceState{}.sequenceId; // Generate new sequenceId
+ auto& state = mCurrentState.displays.editValueFor(token->get());
+ state.sequenceId = DisplayDeviceState{}.sequenceId; // Generate new sequenceId.
state.physical->supportedModes = std::move(supportedModes);
state.physical->activeMode = std::move(activeMode);
if (getHwComposer().updatesDeviceProductInfoOnHotplugReconnect()) {
@@ -2815,13 +2778,13 @@
} else {
ALOGV("Removing display %s", to_string(displayId).c_str());
- const ssize_t index = mCurrentState.displays.indexOfKey(it->second);
- if (index >= 0) {
+ if (const ssize_t index = mCurrentState.displays.indexOfKey(token->get()); index >= 0) {
const DisplayDeviceState& state = mCurrentState.displays.valueAt(index);
mInterceptor->saveDisplayDeletion(state.sequenceId);
mCurrentState.displays.removeItemsAt(index);
}
- mPhysicalDisplayTokens.erase(it);
+
+ mPhysicalDisplayTokens.erase(displayId);
}
processDisplayChangesLocked();
@@ -2869,7 +2832,7 @@
}
if (const auto id = PhysicalDisplayId::tryCast(compositionDisplay->getId())) {
- creationArgs.isPrimary = id == getInternalDisplayIdLocked();
+ creationArgs.isPrimary = id == getPrimaryDisplayIdLocked();
if (useColorManagement) {
std::vector<ColorMode> modes = getHwComposer().getColorModes(*id);
@@ -2923,7 +2886,8 @@
RenderIntent::COLORIMETRIC,
Dataspace::UNKNOWN});
if (!state.isVirtual()) {
- MAIN_THREAD_GUARD(display->setActiveMode(state.physical->activeMode->getId()));
+ FTL_FAKE_GUARD(kMainThreadContext,
+ display->setActiveMode(state.physical->activeMode->getId()));
display->setDeviceProductInfo(state.physical->deviceProductInfo);
}
@@ -2968,7 +2932,7 @@
builder.setPixels(resolution);
builder.setIsSecure(state.isSecure);
- builder.setPowerAdvisor(&mPowerAdvisor);
+ builder.setPowerAdvisor(mPowerAdvisor.get());
builder.setName(state.displayName);
auto compositionDisplay = getCompositionEngine().createDisplay(builder.build());
compositionDisplay->setLayerCachingEnabled(mLayerCachingEnabled);
@@ -3001,15 +2965,16 @@
}
LOG_FATAL_IF(!displaySurface);
- const auto display = setupNewDisplayDeviceInternal(displayToken, std::move(compositionDisplay),
- state, displaySurface, producer);
- mDisplays.emplace(displayToken, display);
+ auto display = setupNewDisplayDeviceInternal(displayToken, std::move(compositionDisplay), state,
+ displaySurface, producer);
if (display->isPrimary()) {
initScheduler(display);
}
if (!state.isVirtual()) {
dispatchDisplayHotplugEvent(display->getPhysicalId(), true);
}
+
+ mDisplays.try_emplace(displayToken, std::move(display));
}
void SurfaceFlinger::processDisplayRemoved(const wp<IBinder>& displayToken) {
@@ -3293,12 +3258,15 @@
return;
}
- for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
+ for (const auto& [_, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) {
if (const auto brightness = display->getStagedBrightness(); brightness) {
if (!needsComposite) {
const status_t error =
getHwComposer()
.setDisplayBrightness(display->getPhysicalId(), *brightness,
+ display->getCompositionDisplay()
+ ->getState()
+ .displayBrightnessNits,
Hwc2::Composer::DisplayBrightnessOptions{
.applyImmediately = true})
.get();
@@ -3316,7 +3284,7 @@
std::vector<DisplayInfo>& outDisplayInfos) {
ftl::SmallMap<ui::LayerStack, DisplayDevice::InputInfo, 4> displayInputInfos;
- for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
+ for (const auto& [_, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) {
const auto layerStack = display->getLayerStack();
const auto info = display->getInputInfo();
@@ -3361,7 +3329,7 @@
void SurfaceFlinger::updateCursorAsync() {
compositionengine::CompositionRefreshArgs refreshArgs;
- for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
+ for (const auto& [_, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) {
if (HalDisplayId::tryCast(display->getId())) {
refreshArgs.outputs.push_back(display->getCompositionDisplay());
}
@@ -3546,7 +3514,7 @@
}
void SurfaceFlinger::invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty) {
- for (const auto& [token, displayDevice] : ON_MAIN_THREAD(mDisplays)) {
+ for (const auto& [token, displayDevice] : FTL_FAKE_GUARD(mStateLock, mDisplays)) {
auto display = displayDevice->getCompositionDisplay();
if (display->includesLayer(layer->getOutputFilter())) {
display->editState().dirtyRegion.orSelf(dirty);
@@ -3647,6 +3615,23 @@
if (mNumLayers >= ISurfaceComposer::MAX_LAYERS) {
ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers.load(),
ISurfaceComposer::MAX_LAYERS);
+ static_cast<void>(mScheduler->schedule([=] {
+ ALOGE("Dumping random sampling of on-screen layers: ");
+ mDrawingState.traverse([&](Layer *layer) {
+ // Aim to dump about 200 layers to avoid totally trashing
+ // logcat. On the other hand, if there really are 4096 layers
+ // something has gone totally wrong its probably the most
+ // useful information in logcat.
+ if (rand() % 20 == 13) {
+ ALOGE("Layer: %s", layer->getName().c_str());
+ }
+ });
+ for (Layer* offscreenLayer : mOffscreenLayers) {
+ if (rand() % 20 == 13) {
+ ALOGE("Offscreen-layer: %s", offscreenLayer->getName().c_str());
+ }
+ }
+ }));
return NO_MEMORY;
}
@@ -3677,11 +3662,11 @@
}
void SurfaceFlinger::setTransactionFlags(uint32_t mask, TransactionSchedule schedule,
- const sp<IBinder>& applyToken) {
+ const sp<IBinder>& applyToken, FrameHint frameHint) {
modulateVsync(&VsyncModulator::setTransactionSchedule, schedule, applyToken);
if (const bool scheduled = mTransactionFlags.fetch_or(mask) & mask; !scheduled) {
- scheduleCommit(FrameHint::kActive);
+ scheduleCommit(frameHint);
}
}
@@ -4053,7 +4038,7 @@
}
void SurfaceFlinger::queueTransaction(TransactionState& state) {
- Mutex::Autolock _l(mQueueLock);
+ Mutex::Autolock lock(mQueueLock);
// Generate a CountDownLatch pending state if this is a synchronous transaction.
if ((state.flags & eSynchronous) || state.inputWindowCommands.syncInputWindows) {
@@ -4072,7 +4057,9 @@
return TransactionSchedule::Late;
}(state.flags);
- setTransactionFlags(eTransactionFlushNeeded, schedule, state.applyToken);
+ const auto frameHint = state.isFrameActive() ? FrameHint::kActive : FrameHint::kNone;
+
+ setTransactionFlags(eTransactionFlushNeeded, schedule, state.applyToken, frameHint);
}
void SurfaceFlinger::waitForSynchronousTransaction(
@@ -4534,6 +4521,9 @@
if (what & layer_state_t::eAutoRefreshChanged) {
layer->setAutoRefresh(s.autoRefresh);
}
+ if (what & layer_state_t::eDimmingEnabledChanged) {
+ if (layer->setDimmingEnabled(s.dimmingEnabled)) flags |= eTraversalNeeded;
+ }
if (what & layer_state_t::eTrustedOverlayChanged) {
if (layer->setTrustedOverlay(s.isTrustedOverlay)) {
flags |= eTraversalNeeded;
@@ -4832,7 +4822,8 @@
void SurfaceFlinger::initializeDisplays() {
// Async since we may be called from the main thread.
- static_cast<void>(mScheduler->schedule([this]() MAIN_THREAD { onInitializeDisplays(); }));
+ static_cast<void>(
+ mScheduler->schedule([this]() FTL_FAKE_GUARD(mStateLock) { onInitializeDisplays(); }));
}
void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode) {
@@ -4932,7 +4923,7 @@
}
void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) {
- auto future = mScheduler->schedule([=]() MAIN_THREAD {
+ auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
const auto display = getDisplayDeviceLocked(displayToken);
if (!display) {
ALOGE("Attempt to set power mode %d for invalid display token %p", mode,
@@ -4960,7 +4951,9 @@
pid, uid);
} else {
static const std::unordered_map<std::string, Dumper> dumpers = {
+ {"--comp-displays"s, dumper(&SurfaceFlinger::dumpCompositionDisplays)},
{"--display-id"s, dumper(&SurfaceFlinger::dumpDisplayIdentificationData)},
+ {"--displays"s, dumper(&SurfaceFlinger::dumpDisplays)},
{"--dispsync"s, dumper([this](std::string& s) { mScheduler->dumpVsync(s); })},
{"--edid"s, argsDumper(&SurfaceFlinger::dumpRawDisplayIdentificationData)},
{"--frame-events"s, dumper(&SurfaceFlinger::dumpFrameEventsLocked)},
@@ -4979,7 +4972,7 @@
bool dumpLayers = true;
{
- TimedLock lock(mStateLock, s2ns(1), __FUNCTION__);
+ TimedLock lock(mStateLock, s2ns(1), __func__);
if (!lock.locked()) {
StringAppendF(&result, "Dumping without lock after timeout: %s (%d)\n",
strerror(-lock.status), lock.status);
@@ -5067,8 +5060,6 @@
mFrameTimeline->parseArgs(args, result);
}
-// This should only be called from the main thread. Otherwise it would need
-// the lock and should use mCurrentState rather than mDrawingState.
void SurfaceFlinger::logFrameStats() {
mDrawingState.traverse([&](Layer* layer) {
layer->logFrameStats();
@@ -5139,6 +5130,20 @@
[&] (Layer* layer) { layer->dumpFrameEvents(result); });
}
+void SurfaceFlinger::dumpCompositionDisplays(std::string& result) const {
+ for (const auto& [token, display] : mDisplays) {
+ display->getCompositionDisplay()->dump(result);
+ result += '\n';
+ }
+}
+
+void SurfaceFlinger::dumpDisplays(std::string& result) const {
+ for (const auto& [token, display] : mDisplays) {
+ display->dump(result);
+ result += '\n';
+ }
+}
+
void SurfaceFlinger::dumpDisplayIdentificationData(std::string& result) const {
for (const auto& [token, display] : mDisplays) {
const auto displayId = PhysicalDisplayId::tryCast(display->getId());
@@ -5226,7 +5231,7 @@
}
void SurfaceFlinger::dumpDisplayProto(LayersTraceProto& layersTraceProto) const {
- for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
+ for (const auto& [_, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) {
DisplayProto* displayProto = layersTraceProto.add_displays();
displayProto->set_id(display->getId().value);
displayProto->set_name(display->getDisplayName());
@@ -5347,21 +5352,12 @@
});
}
- /*
- * Dump Display state
- */
-
colorizer.bold(result);
StringAppendF(&result, "Displays (%zu entries)\n", mDisplays.size());
colorizer.reset(result);
- for (const auto& [token, display] : mDisplays) {
- display->dump(result);
- }
- result.append("\n");
-
- /*
- * Dump CompositionEngine state
- */
+ dumpDisplays(result);
+ dumpCompositionDisplays(result);
+ result.push_back('\n');
mCompositionEngine->dump(result);
@@ -5513,30 +5509,21 @@
// access to SF.
case BOOT_FINISHED:
case CLEAR_ANIMATION_FRAME_STATS:
- case CREATE_DISPLAY:
- case DESTROY_DISPLAY:
case GET_ANIMATION_FRAME_STATS:
case OVERRIDE_HDR_TYPES:
case GET_HDR_CAPABILITIES:
case SET_DESIRED_DISPLAY_MODE_SPECS:
case GET_DESIRED_DISPLAY_MODE_SPECS:
case SET_ACTIVE_COLOR_MODE:
- case GET_BOOT_DISPLAY_MODE_SUPPORT:
case SET_BOOT_DISPLAY_MODE:
- case CLEAR_BOOT_DISPLAY_MODE:
case GET_AUTO_LOW_LATENCY_MODE_SUPPORT:
- case SET_AUTO_LOW_LATENCY_MODE:
case GET_GAME_CONTENT_TYPE_SUPPORT:
- case SET_GAME_CONTENT_TYPE:
- case SET_POWER_MODE:
case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES:
case SET_DISPLAY_CONTENT_SAMPLING_ENABLED:
case GET_DISPLAYED_CONTENT_SAMPLE:
case ADD_TUNNEL_MODE_ENABLED_LISTENER:
case REMOVE_TUNNEL_MODE_ENABLED_LISTENER:
- case NOTIFY_POWER_BOOST:
case SET_GLOBAL_SHADOW_SETTINGS:
- case GET_PRIMARY_PHYSICAL_DISPLAY_ID:
case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: {
// OVERRIDE_HDR_TYPES is used by CTS tests, which acquire the necessary
// permission dynamically. Don't use the permission cache for this check.
@@ -5567,15 +5554,11 @@
case AUTHENTICATE_SURFACE:
case GET_ACTIVE_COLOR_MODE:
case GET_ACTIVE_DISPLAY_MODE:
- case GET_PHYSICAL_DISPLAY_IDS:
- case GET_PHYSICAL_DISPLAY_TOKEN:
case GET_DISPLAY_COLOR_MODES:
case GET_DISPLAY_NATIVE_PRIMARIES:
case GET_STATIC_DISPLAY_INFO:
case GET_DYNAMIC_DISPLAY_INFO:
case GET_DISPLAY_MODES:
- case GET_DISPLAY_STATE:
- case GET_DISPLAY_STATS:
case GET_SUPPORTED_FRAME_TIMESTAMPS:
// Calling setTransactionState is safe, because you need to have been
// granted a reference to Client* and Handle* to do anything with it.
@@ -5584,11 +5567,9 @@
case GET_COLOR_MANAGEMENT:
case GET_COMPOSITION_PREFERENCE:
case GET_PROTECTED_CONTENT_SUPPORT:
- case IS_WIDE_COLOR_DISPLAY:
// setFrameRate() is deliberately available for apps to call without any
// special permissions.
case SET_FRAME_RATE:
- case GET_DISPLAY_BRIGHTNESS_SUPPORT:
case GET_DISPLAY_DECORATION_SUPPORT:
case SET_FRAME_TIMELINE_INFO:
case GET_GPU_CONTEXT_PRIORITY:
@@ -5596,19 +5577,6 @@
// This is not sensitive information, so should not require permission control.
return OK;
}
- case SET_DISPLAY_BRIGHTNESS:
- case ADD_HDR_LAYER_INFO_LISTENER:
- case REMOVE_HDR_LAYER_INFO_LISTENER: {
- IPCThreadState* ipc = IPCThreadState::self();
- const int pid = ipc->getCallingPid();
- const int uid = ipc->getCallingUid();
- if ((uid != AID_GRAPHICS) &&
- !PermissionCache::checkPermission(sControlDisplayBrightness, pid, uid)) {
- ALOGE("Permission Denial: can't control brightness pid=%d, uid=%d", pid, uid);
- return PERMISSION_DENIED;
- }
- return OK;
- }
case ADD_FPS_LISTENER:
case REMOVE_FPS_LISTENER:
case ADD_REGION_SAMPLING_LISTENER:
@@ -5654,10 +5622,28 @@
}
return PERMISSION_DENIED;
}
+ case CREATE_DISPLAY:
+ case DESTROY_DISPLAY:
+ case GET_PRIMARY_PHYSICAL_DISPLAY_ID:
+ case GET_PHYSICAL_DISPLAY_IDS:
+ case GET_PHYSICAL_DISPLAY_TOKEN:
+ case SET_POWER_MODE:
+ case GET_DISPLAY_STATE:
+ case GET_DISPLAY_STATS:
+ case CLEAR_BOOT_DISPLAY_MODE:
+ case GET_BOOT_DISPLAY_MODE_SUPPORT:
+ case SET_AUTO_LOW_LATENCY_MODE:
+ case SET_GAME_CONTENT_TYPE:
case CAPTURE_LAYERS:
case CAPTURE_DISPLAY:
case CAPTURE_DISPLAY_BY_ID:
- LOG_FATAL("Deprecated opcode: %d", code);
+ case IS_WIDE_COLOR_DISPLAY:
+ case GET_DISPLAY_BRIGHTNESS_SUPPORT:
+ case SET_DISPLAY_BRIGHTNESS:
+ case ADD_HDR_LAYER_INFO_LISTENER:
+ case REMOVE_HDR_LAYER_INFO_LISTENER:
+ case NOTIFY_POWER_BOOST:
+ LOG_FATAL("Deprecated opcode: %d, migrated to AIDL", code);
return PERMISSION_DENIED;
}
@@ -5867,7 +5853,7 @@
int64_t startingTime =
(fixedStartingTime) ? fixedStartingTime : systemTime();
mScheduler
- ->schedule([&]() MAIN_THREAD {
+ ->schedule([&]() FTL_FAKE_GUARD(mStateLock) {
mLayerTracing.notify("start", startingTime);
})
.wait();
@@ -5980,10 +5966,12 @@
switch (n = data.readInt32()) {
case 0:
case 1:
- ON_MAIN_THREAD(enableRefreshRateOverlay(static_cast<bool>(n)));
+ FTL_FAKE_GUARD(mStateLock,
+ enableRefreshRateOverlay(static_cast<bool>(n)));
break;
default: {
- reply->writeBool(ON_MAIN_THREAD(isRefreshRateOverlayEnabled()));
+ reply->writeBool(
+ FTL_FAKE_GUARD(mStateLock, isRefreshRateOverlayEnabled()));
}
}
});
@@ -6021,7 +6009,7 @@
return mScheduler
->schedule([this] {
const auto display =
- ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
+ FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked());
// This is a little racy, but not in a way that hurts anything. As
// we grab the defaultMode from the display manager policy, we could
@@ -6043,7 +6031,7 @@
return mScheduler
->schedule([this] {
const auto display =
- ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
+ FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked());
constexpr bool kOverridePolicy = true;
return setDesiredDisplayModeSpecsInternal(display, {},
kOverridePolicy);
@@ -6159,7 +6147,7 @@
// Update the overlay on the main thread to avoid race conditions with
// mRefreshRateConfigs->getActiveMode()
static_cast<void>(mScheduler->schedule([=] {
- const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
+ const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked());
if (!display) {
ALOGW("%s: default display is null", __func__);
return;
@@ -6720,6 +6708,7 @@
captureResults.buffer = buffer->getBuffer();
auto dataspace = renderArea.getReqDataSpace();
auto parent = renderArea.getParentLayer();
+ auto renderIntent = RenderIntent::TONE_MAP_COLORIMETRIC;
if ((dataspace == ui::Dataspace::UNKNOWN) && (parent != nullptr)) {
Mutex::Autolock lock(mStateLock);
auto display = findDisplay([layerStack = parent->getLayerStack()](const auto& display) {
@@ -6732,6 +6721,7 @@
const ui::ColorMode colorMode = display->getCompositionDisplay()->getState().colorMode;
dataspace = pickDataspaceFromColorMode(colorMode);
+ renderIntent = display->getCompositionDisplay()->getState().renderIntent;
}
captureResults.capturedDataspace = dataspace;
@@ -6753,6 +6743,8 @@
clientCompositionDisplay.outputDataspace = dataspace;
clientCompositionDisplay.maxLuminance = DisplayDevice::sDefaultMaxLumiance;
+ clientCompositionDisplay.renderIntent =
+ static_cast<aidl::android::hardware::graphics::composer3::RenderIntent>(renderIntent);
const float colorSaturation = grayscale ? 0 : 1;
clientCompositionDisplay.colorTransform = calculateColorMatrix(colorSaturation);
@@ -6957,7 +6949,7 @@
}
auto future = mScheduler->schedule([=]() -> status_t {
- const auto display = ON_MAIN_THREAD(getDisplayDeviceLocked(displayToken));
+ const auto display = FTL_FAKE_GUARD(mStateLock, getDisplayDeviceLocked(displayToken));
if (!display) {
ALOGE("Attempt to set desired display modes for invalid display token %p",
displayToken.get());
@@ -7202,7 +7194,7 @@
if (const auto frameRateOverride = mScheduler->getFrameRateOverride(uid)) {
refreshRate = *frameRateOverride;
} else if (!getHwComposer().isHeadless()) {
- if (const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked())) {
+ if (const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked())) {
refreshRate = display->refreshRateConfigs().getActiveMode()->getFps();
}
}
@@ -7216,15 +7208,6 @@
return calculateMaxAcquiredBufferCount(refreshRate, presentLatency);
}
-void TransactionState::traverseStatesWithBuffers(
- std::function<void(const layer_state_t&)> visitor) {
- for (const auto& state : states) {
- if (state.state.hasBufferChanges() && state.state.hasValidBuffer() && state.state.surface) {
- visitor(state.state);
- }
- }
-}
-
void SurfaceFlinger::handleLayerCreatedLocked(const LayerCreatedState& state) {
sp<Layer> layer = state.layer.promote();
if (!layer) {
@@ -7360,6 +7343,123 @@
}
// gui::ISurfaceComposer
+
+binder::Status SurfaceComposerAIDL::createDisplay(const std::string& displayName, bool secure,
+ sp<IBinder>* outDisplay) {
+ status_t status = checkAccessPermission();
+ if (status == OK) {
+ String8 displayName8 = String8::format("%s", displayName.c_str());
+ *outDisplay = mFlinger->createDisplay(displayName8, secure);
+ return binder::Status::ok();
+ }
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::destroyDisplay(const sp<IBinder>& display) {
+ status_t status = checkAccessPermission();
+ if (status == OK) {
+ mFlinger->destroyDisplay(display);
+ return binder::Status::ok();
+ }
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getPhysicalDisplayIds(std::vector<int64_t>* outDisplayIds) {
+ std::vector<PhysicalDisplayId> physicalDisplayIds = mFlinger->getPhysicalDisplayIds();
+ std::vector<int64_t> displayIds;
+ displayIds.reserve(physicalDisplayIds.size());
+ for (auto item : physicalDisplayIds) {
+ displayIds.push_back(static_cast<int64_t>(item.value));
+ }
+ *outDisplayIds = displayIds;
+ return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::getPrimaryPhysicalDisplayId(int64_t* outDisplayId) {
+ status_t status = checkAccessPermission();
+ if (status != OK) {
+ return binder::Status::fromStatusT(status);
+ }
+
+ PhysicalDisplayId id;
+ status = mFlinger->getPrimaryPhysicalDisplayId(&id);
+ if (status == NO_ERROR) {
+ *outDisplayId = id.value;
+ }
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getPhysicalDisplayToken(int64_t displayId,
+ sp<IBinder>* outDisplay) {
+ const auto id = DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(displayId));
+ *outDisplay = mFlinger->getPhysicalDisplayToken(*id);
+ return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::setPowerMode(const sp<IBinder>& display, int mode) {
+ status_t status = checkAccessPermission();
+ if (status != OK) return binder::Status::fromStatusT(status);
+
+ mFlinger->setPowerMode(display, mode);
+ return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::getDisplayStats(const sp<IBinder>& display,
+ gui::DisplayStatInfo* outStatInfo) {
+ DisplayStatInfo statInfo;
+ status_t status = mFlinger->getDisplayStats(display, &statInfo);
+ if (status == NO_ERROR) {
+ outStatInfo->vsyncTime = static_cast<long>(statInfo.vsyncTime);
+ outStatInfo->vsyncPeriod = static_cast<long>(statInfo.vsyncPeriod);
+ }
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getDisplayState(const sp<IBinder>& display,
+ gui::DisplayState* outState) {
+ ui::DisplayState state;
+ status_t status = mFlinger->getDisplayState(display, &state);
+ if (status == NO_ERROR) {
+ outState->layerStack = state.layerStack.id;
+ outState->orientation = static_cast<gui::Rotation>(state.orientation);
+ outState->layerStackSpaceRect.width = state.layerStackSpaceRect.width;
+ outState->layerStackSpaceRect.height = state.layerStackSpaceRect.height;
+ }
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::clearBootDisplayMode(const sp<IBinder>& display) {
+ status_t status = checkAccessPermission();
+ if (status != OK) return binder::Status::fromStatusT(status);
+
+ status = mFlinger->clearBootDisplayMode(display);
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getBootDisplayModeSupport(bool* outMode) {
+ status_t status = checkAccessPermission();
+ if (status != OK) return binder::Status::fromStatusT(status);
+
+ status = mFlinger->getBootDisplayModeSupport(outMode);
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::setAutoLowLatencyMode(const sp<IBinder>& display, bool on) {
+ status_t status = checkAccessPermission();
+ if (status != OK) return binder::Status::fromStatusT(status);
+
+ mFlinger->setAutoLowLatencyMode(display, on);
+ return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::setGameContentType(const sp<IBinder>& display, bool on) {
+ status_t status = checkAccessPermission();
+ if (status != OK) return binder::Status::fromStatusT(status);
+
+ mFlinger->setGameContentType(display, on);
+ return binder::Status::ok();
+}
+
binder::Status SurfaceComposerAIDL::captureDisplay(
const DisplayCaptureArgs& args, const sp<IScreenCaptureListener>& captureListener) {
status_t status = mFlinger->captureDisplay(args, captureListener);
@@ -7386,6 +7486,75 @@
return binder::Status::fromStatusT(status);
}
+binder::Status SurfaceComposerAIDL::isWideColorDisplay(const sp<IBinder>& token,
+ bool* outIsWideColorDisplay) {
+ status_t status = mFlinger->isWideColorDisplay(token, outIsWideColorDisplay);
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
+ bool* outSupport) {
+ status_t status = mFlinger->getDisplayBrightnessSupport(displayToken, outSupport);
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::setDisplayBrightness(const sp<IBinder>& displayToken,
+ const gui::DisplayBrightness& brightness) {
+ status_t status = checkControlDisplayBrightnessPermission();
+ if (status != OK) return binder::Status::fromStatusT(status);
+
+ status = mFlinger->setDisplayBrightness(displayToken, brightness);
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::addHdrLayerInfoListener(
+ const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) {
+ status_t status = checkControlDisplayBrightnessPermission();
+ if (status != OK) return binder::Status::fromStatusT(status);
+
+ status = mFlinger->addHdrLayerInfoListener(displayToken, listener);
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::removeHdrLayerInfoListener(
+ const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) {
+ status_t status = checkControlDisplayBrightnessPermission();
+ if (status != OK) return binder::Status::fromStatusT(status);
+
+ status = mFlinger->removeHdrLayerInfoListener(displayToken, listener);
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::notifyPowerBoost(int boostId) {
+ status_t status = checkAccessPermission();
+ if (status != OK) return binder::Status::fromStatusT(status);
+
+ status = mFlinger->notifyPowerBoost(boostId);
+ return binder::Status::fromStatusT(status);
+}
+
+status_t SurfaceComposerAIDL::checkAccessPermission(bool usePermissionCache) {
+ if (!mFlinger->callingThreadHasUnscopedSurfaceFlingerAccess(usePermissionCache)) {
+ IPCThreadState* ipc = IPCThreadState::self();
+ ALOGE("Permission Denial: can't access SurfaceFlinger pid=%d, uid=%d", ipc->getCallingPid(),
+ ipc->getCallingUid());
+ return PERMISSION_DENIED;
+ }
+ return OK;
+}
+
+status_t SurfaceComposerAIDL::checkControlDisplayBrightnessPermission() {
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ if ((uid != AID_GRAPHICS) &&
+ !PermissionCache::checkPermission(sControlDisplayBrightness, pid, uid)) {
+ ALOGE("Permission Denial: can't control brightness pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+ return OK;
+}
+
} // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index f2636b4..74e0407 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -7,7 +7,6 @@
*
* 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
@@ -24,8 +23,11 @@
#include <android-base/thread_annotations.h>
#include <android/gui/BnSurfaceComposer.h>
+#include <android/gui/DisplayStatInfo.h>
+#include <android/gui/DisplayState.h>
#include <cutils/atomic.h>
#include <cutils/compiler.h>
+#include <ftl/small_map.h>
#include <gui/BufferQueue.h>
#include <gui/FrameTimestamps.h>
#include <gui/ISurfaceComposer.h>
@@ -64,6 +66,7 @@
#include "Scheduler/Scheduler.h"
#include "Scheduler/VsyncModulator.h"
#include "SurfaceFlingerFactory.h"
+#include "ThreadContext.h"
#include "TracedOrdinal.h"
#include "Tracing/LayerTracing.h"
#include "Tracing/TransactionTracing.h"
@@ -183,11 +186,6 @@
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,
@@ -346,6 +344,11 @@
void disableExpensiveRendering();
FloatRect getMaxDisplayBounds();
+ // If set, composition engine tries to predict the composition strategy provided by HWC
+ // based on the previous frame. If the strategy can be predicted, gpu composition will
+ // run parallel to the hwc validateDisplay call and re-run if the predition is incorrect.
+ bool mPredictCompositionStrategy = false;
+
protected:
// We're reference counted, never destroy SurfaceFlinger directly
virtual ~SurfaceFlinger();
@@ -524,15 +527,15 @@
// Implements ISurfaceComposer
sp<ISurfaceComposerClient> createConnection() override;
- sp<IBinder> createDisplay(const String8& displayName, bool secure) override;
- void destroyDisplay(const sp<IBinder>& displayToken) override;
- std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override EXCLUDES(mStateLock) {
+ sp<IBinder> createDisplay(const String8& displayName, bool secure);
+ void destroyDisplay(const sp<IBinder>& displayToken);
+ std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const EXCLUDES(mStateLock) {
Mutex::Autolock lock(mStateLock);
return getPhysicalDisplayIdsLocked();
}
- status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const override EXCLUDES(mStateLock);
+ status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const EXCLUDES(mStateLock);
- sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const override;
+ sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const;
status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo,
const Vector<ComposerState>& state,
const Vector<DisplayState>& displays, uint32_t flags,
@@ -554,9 +557,9 @@
status_t captureDisplay(DisplayId, const sp<IScreenCaptureListener>&);
status_t captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&);
- status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats) override;
+ status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats);
status_t getDisplayState(const sp<IBinder>& displayToken, ui::DisplayState*)
- EXCLUDES(mStateLock) override;
+ EXCLUDES(mStateLock);
status_t getStaticDisplayInfo(const sp<IBinder>& displayToken, ui::StaticDisplayInfo*)
EXCLUDES(mStateLock) override;
status_t getDynamicDisplayInfo(const sp<IBinder>& displayToken, ui::DynamicDisplayInfo*)
@@ -564,12 +567,12 @@
status_t getDisplayNativePrimaries(const sp<IBinder>& displayToken,
ui::DisplayPrimaries&) override;
status_t setActiveColorMode(const sp<IBinder>& displayToken, ui::ColorMode colorMode) override;
- status_t getBootDisplayModeSupport(bool* outSupport) const override;
+ status_t getBootDisplayModeSupport(bool* outSupport) const;
status_t setBootDisplayMode(const sp<IBinder>& displayToken, ui::DisplayModeId id) override;
- status_t clearBootDisplayMode(const sp<IBinder>& displayToken) override;
- void setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on) override;
- void setGameContentType(const sp<IBinder>& displayToken, bool on) override;
- void setPowerMode(const sp<IBinder>& displayToken, int mode) override;
+ status_t clearBootDisplayMode(const sp<IBinder>& displayToken);
+ void setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on);
+ void setGameContentType(const sp<IBinder>& displayToken, bool on);
+ void setPowerMode(const sp<IBinder>& displayToken, int mode);
status_t clearAnimationFrameStats() override;
status_t getAnimationFrameStats(FrameStats* outStats) const override;
status_t overrideHdrTypes(const sp<IBinder>& displayToken,
@@ -592,8 +595,7 @@
uint64_t timestamp,
DisplayedFrameStats* outStats) const override;
status_t getProtectedContentSupport(bool* outSupported) const override;
- status_t isWideColorDisplay(const sp<IBinder>& displayToken,
- bool* outIsWideColorDisplay) const override;
+ status_t isWideColorDisplay(const sp<IBinder>& displayToken, bool* outIsWideColorDisplay) const;
status_t addRegionSamplingListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
const sp<IRegionSamplingListener>& listener) override;
status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) override;
@@ -615,15 +617,14 @@
float* outPrimaryRefreshRateMax,
float* outAppRequestRefreshRateMin,
float* outAppRequestRefreshRateMax) override;
- status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
- bool* outSupport) const override;
+ status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken, bool* outSupport) const;
status_t setDisplayBrightness(const sp<IBinder>& displayToken,
- const gui::DisplayBrightness& brightness) override;
+ const gui::DisplayBrightness& brightness);
status_t addHdrLayerInfoListener(const sp<IBinder>& displayToken,
- const sp<gui::IHdrLayerInfoListener>& listener) override;
+ const sp<gui::IHdrLayerInfoListener>& listener);
status_t removeHdrLayerInfoListener(const sp<IBinder>& displayToken,
- const sp<gui::IHdrLayerInfoListener>& listener) override;
- status_t notifyPowerBoost(int32_t boostId) override;
+ const sp<gui::IHdrLayerInfoListener>& listener);
+ status_t notifyPowerBoost(int32_t boostId);
status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
float lightPosY, float lightPosZ, float lightRadius) override;
status_t getDisplayDecorationSupport(
@@ -740,7 +741,7 @@
void updateLayerGeometry();
void updateInputFlinger();
- void persistDisplayBrightness(bool needsComposite) REQUIRES(SF_MAIN_THREAD);
+ void persistDisplayBrightness(bool needsComposite) REQUIRES(kMainThreadContext);
void buildWindowInfos(std::vector<gui::WindowInfo>& outWindowInfos,
std::vector<gui::DisplayInfo>& outDisplayInfos);
void commitInputWindowCommands() REQUIRES(mStateLock);
@@ -788,7 +789,8 @@
// Sets the masked bits, and schedules a commit if needed.
void setTransactionFlags(uint32_t mask, TransactionSchedule = TransactionSchedule::Late,
- const sp<IBinder>& applyToken = nullptr);
+ const sp<IBinder>& applyToken = nullptr,
+ FrameHint = FrameHint::kActive);
// Clears and returns the masked bits.
uint32_t clearTransactionFlags(uint32_t mask);
@@ -891,8 +893,8 @@
}
sp<DisplayDevice> getDisplayDeviceLocked(const wp<IBinder>& displayToken) REQUIRES(mStateLock) {
- const auto it = mDisplays.find(displayToken);
- return it == mDisplays.end() ? nullptr : it->second;
+ const sp<DisplayDevice> nullDisplay;
+ return mDisplays.get(displayToken).value_or(std::cref(nullDisplay));
}
sp<const DisplayDevice> getDisplayDeviceLocked(PhysicalDisplayId id) const
@@ -907,6 +909,13 @@
return nullptr;
}
+ sp<const DisplayDevice> getDisplayDeviceLocked(DisplayId id) const REQUIRES(mStateLock) {
+ // TODO(b/182939859): Replace tokens with IDs for display lookup.
+ return findDisplay([id](const auto& display) { return display.getId() == id; });
+ }
+
+ // Returns the primary display or (for foldables) the active display, assuming that the inner
+ // and outer displays have mutually exclusive power states.
sp<const DisplayDevice> getDefaultDisplayDeviceLocked() const REQUIRES(mStateLock) {
return const_cast<SurfaceFlinger*>(this)->getDefaultDisplayDeviceLocked();
}
@@ -915,12 +924,9 @@
if (const auto display = getDisplayDeviceLocked(mActiveDisplayToken)) {
return display;
}
- // The active display is outdated, fall back to the internal display
+ // The active display is outdated, so fall back to the primary display.
mActiveDisplayToken.clear();
- if (const auto token = getInternalDisplayTokenLocked()) {
- return getDisplayDeviceLocked(token);
- }
- return nullptr;
+ return getDisplayDeviceLocked(getPrimaryDisplayTokenLocked());
}
sp<const DisplayDevice> getDefaultDisplayDevice() const EXCLUDES(mStateLock) {
@@ -937,11 +943,6 @@
return it == mDisplays.end() ? nullptr : it->second;
}
- sp<const DisplayDevice> getDisplayDeviceLocked(DisplayId id) const REQUIRES(mStateLock) {
- // TODO(b/182939859): Replace tokens with IDs for display lookup.
- return findDisplay([id](const auto& display) { return display.getId() == id; });
- }
-
std::vector<PhysicalDisplayId> getPhysicalDisplayIdsLocked() const REQUIRES(mStateLock);
// mark a region of a layer stack dirty. this updates the dirty
@@ -973,7 +974,7 @@
void setCompositorTimingSnapped(const DisplayStatInfo& stats,
nsecs_t compositeToPresentLatency);
- void postFrame();
+ void postFrame() REQUIRES(kMainThreadContext);
/*
* Display management
@@ -1037,8 +1038,8 @@
*/
sp<IBinder> getPhysicalDisplayTokenLocked(PhysicalDisplayId displayId) const
REQUIRES(mStateLock) {
- const auto it = mPhysicalDisplayTokens.find(displayId);
- return it != mPhysicalDisplayTokens.end() ? it->second : nullptr;
+ const sp<IBinder> nullToken;
+ return mPhysicalDisplayTokens.get(displayId).value_or(std::cref(nullToken));
}
std::optional<PhysicalDisplayId> getPhysicalDisplayIdLocked(
@@ -1051,18 +1052,17 @@
return {};
}
- // TODO(b/182939859): SF conflates the primary (a.k.a. default) display with the first display
- // connected at boot, which is typically internal. (Theoretically, it must be internal because
- // SF does not support disconnecting it, though in practice HWC may circumvent this limitation.)
+ // Returns the first display connected at boot.
//
- // SF inherits getInternalDisplayToken and getInternalDisplayId from ISurfaceComposer, so these
- // locked counterparts are named consistently. Once SF supports headless mode and can designate
- // any display as primary, the "internal" misnomer will be phased out.
- sp<IBinder> getInternalDisplayTokenLocked() const REQUIRES(mStateLock) {
- return getPhysicalDisplayTokenLocked(getInternalDisplayIdLocked());
+ // TODO(b/229851933): SF conflates the primary display with the first display connected at boot,
+ // which typically has DisplayConnectionType::Internal. (Theoretically, it must be an internal
+ // display because SF does not support disconnecting it, though in practice HWC may circumvent
+ // this limitation.)
+ sp<IBinder> getPrimaryDisplayTokenLocked() const REQUIRES(mStateLock) {
+ return getPhysicalDisplayTokenLocked(getPrimaryDisplayIdLocked());
}
- PhysicalDisplayId getInternalDisplayIdLocked() const REQUIRES(mStateLock) {
+ PhysicalDisplayId getPrimaryDisplayIdLocked() const REQUIRES(mStateLock) {
return getHwComposer().getPrimaryDisplayId();
}
@@ -1088,15 +1088,19 @@
void clearStatsLocked(const DumpArgs& args, std::string& result);
void dumpTimeStats(const DumpArgs& args, bool asProto, std::string& result) const;
void dumpFrameTimeline(const DumpArgs& args, std::string& result) const;
- void logFrameStats();
+ void logFrameStats() REQUIRES(kMainThreadContext);
void dumpVSync(std::string& result) const REQUIRES(mStateLock);
void dumpStaticScreenStats(std::string& result) const;
// Not const because each Layer needs to query Fences and cache timestamps.
void dumpFrameEventsLocked(std::string& result);
+
+ void dumpCompositionDisplays(std::string& result) const REQUIRES(mStateLock);
+ void dumpDisplays(std::string& result) const REQUIRES(mStateLock);
void dumpDisplayIdentificationData(std::string& result) const REQUIRES(mStateLock);
void dumpRawDisplayIdentificationData(const DumpArgs&, std::string& result) const;
void dumpWideColorInfo(std::string& result) const REQUIRES(mStateLock);
+
LayersProto dumpDrawingStateProto(uint32_t traceFlags) const;
void dumpOffscreenLayersProto(LayersProto& layersProto,
uint32_t traceFlags = LayerTracing::TRACE_ALL) const;
@@ -1233,10 +1237,14 @@
std::vector<HotplugEvent> mPendingHotplugEvents GUARDED_BY(mStateLock);
- // this may only be written from the main thread with mStateLock held
- // it may be read from other threads with mStateLock held
- std::map<wp<IBinder>, sp<DisplayDevice>> mDisplays GUARDED_BY(mStateLock);
- std::unordered_map<PhysicalDisplayId, sp<IBinder>> mPhysicalDisplayTokens
+ // Displays are composited in `mDisplays` order. Internal displays are inserted at boot and
+ // never removed, so take precedence over external and virtual displays.
+ //
+ // The static capacities were chosen to exceed a typical number of physical/virtual displays.
+ //
+ // May be read from any thread, but must only be written from the main thread.
+ ftl::SmallMap<wp<IBinder>, const sp<DisplayDevice>, 5> mDisplays GUARDED_BY(mStateLock);
+ ftl::SmallMap<PhysicalDisplayId, const sp<IBinder>, 3> mPhysicalDisplayTokens
GUARDED_BY(mStateLock);
struct {
@@ -1369,7 +1377,7 @@
sp<os::IInputFlinger> mInputFlinger;
InputWindowCommands mInputWindowCommands;
- Hwc2::impl::PowerAdvisor mPowerAdvisor;
+ std::unique_ptr<Hwc2::PowerAdvisor> mPowerAdvisor;
void enableRefreshRateOverlay(bool enable) REQUIRES(mStateLock);
@@ -1409,10 +1417,8 @@
std::atomic<ui::Transform::RotationFlags> mActiveDisplayTransformHint;
bool isRefreshRateOverlayEnabled() const REQUIRES(mStateLock) {
- return std::any_of(mDisplays.begin(), mDisplays.end(),
- [](std::pair<wp<IBinder>, sp<DisplayDevice>> display) {
- return display.second->isRefreshRateOverlayEnabled();
- });
+ return hasDisplay(
+ [](const auto& display) { return display.isRefreshRateOverlayEnabled(); });
}
wp<IBinder> mActiveDisplayToken GUARDED_BY(mStateLock);
@@ -1431,7 +1437,7 @@
nsecs_t commitStart;
nsecs_t compositeStart;
nsecs_t presentEnd;
- } mPowerHintSessionData GUARDED_BY(SF_MAIN_THREAD);
+ } mPowerHintSessionData GUARDED_BY(kMainThreadContext);
nsecs_t mAnimationTransactionTimeout = s2ns(5);
@@ -1442,11 +1448,43 @@
public:
SurfaceComposerAIDL(sp<SurfaceFlinger> sf) { mFlinger = sf; }
+ binder::Status createDisplay(const std::string& displayName, bool secure,
+ sp<IBinder>* outDisplay) override;
+ binder::Status destroyDisplay(const sp<IBinder>& display) override;
+ binder::Status getPhysicalDisplayIds(std::vector<int64_t>* outDisplayIds) override;
+ binder::Status getPrimaryPhysicalDisplayId(int64_t* outDisplayId) override;
+ binder::Status getPhysicalDisplayToken(int64_t displayId, sp<IBinder>* outDisplay) override;
+ binder::Status setPowerMode(const sp<IBinder>& display, int mode) override;
+ binder::Status getDisplayStats(const sp<IBinder>& display,
+ gui::DisplayStatInfo* outStatInfo) override;
+ binder::Status getDisplayState(const sp<IBinder>& display,
+ gui::DisplayState* outState) override;
+ binder::Status clearBootDisplayMode(const sp<IBinder>& display) override;
+ binder::Status getBootDisplayModeSupport(bool* outMode) override;
+ binder::Status setAutoLowLatencyMode(const sp<IBinder>& display, bool on) override;
+ binder::Status setGameContentType(const sp<IBinder>& display, bool on) override;
binder::Status captureDisplay(const DisplayCaptureArgs&,
const sp<IScreenCaptureListener>&) override;
binder::Status captureDisplayById(int64_t, const sp<IScreenCaptureListener>&) override;
binder::Status captureLayers(const LayerCaptureArgs&,
const sp<IScreenCaptureListener>&) override;
+ binder::Status isWideColorDisplay(const sp<IBinder>& token,
+ bool* outIsWideColorDisplay) override;
+ binder::Status getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
+ bool* outSupport) override;
+ binder::Status setDisplayBrightness(const sp<IBinder>& displayToken,
+ const gui::DisplayBrightness& brightness) override;
+ binder::Status addHdrLayerInfoListener(const sp<IBinder>& displayToken,
+ const sp<gui::IHdrLayerInfoListener>& listener) override;
+ binder::Status removeHdrLayerInfoListener(
+ const sp<IBinder>& displayToken,
+ const sp<gui::IHdrLayerInfoListener>& listener) override;
+ binder::Status notifyPowerBoost(int boostId) override;
+
+private:
+ static const constexpr bool kUsePermissionCache = true;
+ status_t checkAccessPermission(bool usePermissionCache = kUsePermissionCache);
+ status_t checkControlDisplayBrightnessPermission();
private:
sp<SurfaceFlinger> mFlinger;
diff --git a/services/surfaceflinger/ThreadContext.h b/services/surfaceflinger/ThreadContext.h
new file mode 100644
index 0000000..85c379d
--- /dev/null
+++ b/services/surfaceflinger/ThreadContext.h
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+namespace android {
+
+// Enforces exclusive access by the main thread.
+constexpr class [[clang::capability("mutex")]] {
+} kMainThreadContext;
+
+} // namespace android
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index b1a2bda..e5a9dd4 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -321,22 +321,19 @@
mTimeStats.missedFramesLegacy++;
}
-void TimeStats::incrementClientCompositionFrames() {
- if (!mEnabled.load()) return;
+void TimeStats::pushCompositionStrategyState(const TimeStats::ClientCompositionRecord& record) {
+ if (!mEnabled.load() || !record.hasInterestingData()) {
+ return;
+ }
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.clientCompositionFramesLegacy++;
-}
-
-void TimeStats::incrementClientCompositionReusedFrames() {
- if (!mEnabled.load()) return;
-
- ATRACE_CALL();
-
- std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.clientCompositionReusedFramesLegacy++;
+ if (record.changed) mTimeStats.compositionStrategyChangesLegacy++;
+ if (record.hadClientComposition) mTimeStats.clientCompositionFramesLegacy++;
+ if (record.reused) mTimeStats.clientCompositionReusedFramesLegacy++;
+ if (record.predicted) mTimeStats.compositionStrategyPredictedLegacy++;
+ if (record.predictionSucceeded) mTimeStats.compositionStrategyPredictionSucceededLegacy++;
}
void TimeStats::incrementRefreshRateSwitches() {
@@ -348,15 +345,6 @@
mTimeStats.refreshRateSwitchesLegacy++;
}
-void TimeStats::incrementCompositionStrategyChanges() {
- if (!mEnabled.load()) return;
-
- ATRACE_CALL();
-
- std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.compositionStrategyChangesLegacy++;
-}
-
void TimeStats::recordDisplayEventConnectionCount(int32_t count) {
if (!mEnabled.load()) return;
@@ -1062,8 +1050,10 @@
mTimeStats.missedFramesLegacy = 0;
mTimeStats.clientCompositionFramesLegacy = 0;
mTimeStats.clientCompositionReusedFramesLegacy = 0;
- mTimeStats.refreshRateSwitchesLegacy = 0;
mTimeStats.compositionStrategyChangesLegacy = 0;
+ mTimeStats.compositionStrategyPredictedLegacy = 0;
+ mTimeStats.compositionStrategyPredictionSucceededLegacy = 0;
+ mTimeStats.refreshRateSwitchesLegacy = 0;
mTimeStats.displayEventConnectionsCountLegacy = 0;
mTimeStats.displayOnTimeLegacy = 0;
mTimeStats.presentToPresentLegacy.hist.clear();
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 77c7973..7a159b8 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -45,7 +45,7 @@
virtual ~TimeStats() = default;
// Process a pull request from statsd.
- virtual bool onPullAtom(const int atomId, std::string* pulledData);
+ virtual bool onPullAtom(const int atomId, std::string* pulledData) = 0;
virtual void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) = 0;
virtual bool isEnabled() = 0;
@@ -53,14 +53,8 @@
virtual void incrementTotalFrames() = 0;
virtual void incrementMissedFrames() = 0;
- virtual void incrementClientCompositionFrames() = 0;
- virtual void incrementClientCompositionReusedFrames() = 0;
// Increments the number of times the display refresh rate changed.
virtual void incrementRefreshRateSwitches() = 0;
- // Increments the number of changes in composition strategy
- // The intention is to reflect the number of changes between hwc and gpu
- // composition, where "gpu composition" may also include mixed composition.
- virtual void incrementCompositionStrategyChanges() = 0;
// Records the most up-to-date count of display event connections.
// The stored count will be the maximum ever recoded.
virtual void recordDisplayEventConnectionCount(int32_t count) = 0;
@@ -158,6 +152,24 @@
}
};
+ struct ClientCompositionRecord {
+ // Frame had client composition or mixed composition
+ bool hadClientComposition = false;
+ // Composition changed between hw composition and mixed/client composition
+ bool changed = false;
+ // Frame reused the client composition result from a previous frame
+ bool reused = false;
+ // Composition strategy predicted for frame
+ bool predicted = false;
+ // Composition strategy prediction succeeded
+ bool predictionSucceeded = false;
+
+ // Whether there is data we want to record.
+ bool hasInterestingData() const {
+ return hadClientComposition || changed || reused || predicted;
+ }
+ };
+
virtual void incrementJankyFrames(const JankyFramesInfo& info) = 0;
// Clean up the layer record
virtual void onDestroy(int32_t layerId) = 0;
@@ -169,6 +181,7 @@
// Source of truth is RefrehRateStats.
virtual void recordRefreshRate(uint32_t fps, nsecs_t duration) = 0;
virtual void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) = 0;
+ virtual void pushCompositionStrategyState(const ClientCompositionRecord&) = 0;
};
namespace impl {
@@ -236,10 +249,7 @@
void incrementTotalFrames() override;
void incrementMissedFrames() override;
- void incrementClientCompositionFrames() override;
- void incrementClientCompositionReusedFrames() override;
void incrementRefreshRateSwitches() override;
- void incrementCompositionStrategyChanges() override;
void recordDisplayEventConnectionCount(int32_t count) override;
void recordFrameDuration(nsecs_t startTime, nsecs_t endTime) override;
@@ -275,6 +285,8 @@
void recordRefreshRate(uint32_t fps, nsecs_t duration) override;
void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) override;
+ void pushCompositionStrategyState(const ClientCompositionRecord&) override;
+
static const size_t MAX_NUM_TIME_RECORDS = 64;
private:
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index 69afa2a..cf1ca65 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -143,6 +143,14 @@
clientCompositionReusedFramesLegacy);
StringAppendF(&result, "refreshRateSwitches = %d\n", refreshRateSwitchesLegacy);
StringAppendF(&result, "compositionStrategyChanges = %d\n", compositionStrategyChangesLegacy);
+ StringAppendF(&result, "compositionStrategyPredicted = %d\n",
+ compositionStrategyPredictedLegacy);
+ StringAppendF(&result, "compositionStrategyPredictionSucceeded = %d\n",
+ compositionStrategyPredictionSucceededLegacy);
+ StringAppendF(&result, "compositionStrategyPredictionFailed = %d\n",
+ compositionStrategyPredictedLegacy -
+ compositionStrategyPredictionSucceededLegacy);
+
StringAppendF(&result, "displayOnTime = %" PRId64 " ms\n", displayOnTimeLegacy);
StringAppendF(&result, "displayConfigStats is as below:\n");
for (const auto& [fps, duration] : refreshRateStatsLegacy) {
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index 438561c..237ae8d 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -178,6 +178,8 @@
Histogram frameDurationLegacy;
Histogram renderEngineTimingLegacy;
std::unordered_map<uint32_t, nsecs_t> refreshRateStatsLegacy;
+ int32_t compositionStrategyPredictedLegacy = 0;
+ int32_t compositionStrategyPredictionSucceededLegacy = 0;
std::unordered_map<TimelineStatsKey, TimelineStats, TimelineStatsKey::Hasher> stats;
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
index d249b60..a73eccf 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
@@ -429,7 +429,7 @@
bufferProto.height(), bufferProto.pixel_format(),
bufferProto.usage()));
layer.bufferData->frameNumber = bufferProto.frame_number();
- layer.bufferData->flags = Flags<BufferData::BufferDataChange>(bufferProto.flags());
+ layer.bufferData->flags = ftl::Flags<BufferData::BufferDataChange>(bufferProto.flags());
layer.bufferData->cachedBuffer.id = bufferProto.cached_buffer_id();
layer.bufferData->acquireFence = Fence::NO_FENCE;
}
diff --git a/services/surfaceflinger/TransactionState.h b/services/surfaceflinger/TransactionState.h
index 04ca347..bab5326 100644
--- a/services/surfaceflinger/TransactionState.h
+++ b/services/surfaceflinger/TransactionState.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -16,12 +16,21 @@
#pragma once
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <vector>
+
#include <gui/LayerState.h>
+#include <system/window.h>
namespace android {
+
class CountDownLatch;
struct TransactionState {
+ TransactionState() = default;
+
TransactionState(const FrameTimelineInfo& frameTimelineInfo,
const Vector<ComposerState>& composerStates,
const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
@@ -47,9 +56,30 @@
originUid(originUid),
id(transactionId) {}
- TransactionState() {}
+ // Invokes `void(const layer_state_t&)` visitor for matching layers.
+ template <typename Visitor>
+ void traverseStatesWithBuffers(Visitor&& visitor) const {
+ for (const auto& [state] : states) {
+ if (state.hasBufferChanges() && state.hasValidBuffer() && state.surface) {
+ visitor(state);
+ }
+ }
+ }
- void traverseStatesWithBuffers(std::function<void(const layer_state_t&)> visitor);
+ // TODO(b/185535769): Remove FrameHint. Instead, reset the idle timer (of the relevant physical
+ // display) on the main thread if commit leads to composite. Then, RefreshRateOverlay should be
+ // able to setFrameRate once, rather than for each transaction.
+ bool isFrameActive() const {
+ if (!displays.empty()) return true;
+
+ for (const auto& [state] : states) {
+ if (state.frameRateCompatibility != ANATIVEWINDOW_FRAME_RATE_NO_VOTE) {
+ return true;
+ }
+ }
+
+ return false;
+ }
FrameTimelineInfo frameTimelineInfo;
Vector<ComposerState> states;
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
index 3c4ab95..a605a2f 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
@@ -358,6 +358,7 @@
composer->setLayerPerFrameMetadataBlobs(display, outLayer, std::vector<PerFrameMetadataBlob>{});
composer->setDisplayBrightness(display, mFdp.ConsumeFloatingPoint<float>(),
+ mFdp.ConsumeFloatingPoint<float>(),
Hwc2::Composer::DisplayBrightnessOptions{
.applyImmediately = mFdp.ConsumeIntegral<bool>()});
}
@@ -585,6 +586,7 @@
getDisplayedContentSample(halDisplayID);
mHwc.setDisplayBrightness(mPhysicalDisplayId, mFdp.ConsumeFloatingPoint<float>(),
+ mFdp.ConsumeFloatingPoint<float>(),
Hwc2::Composer::DisplayBrightnessOptions{
.applyImmediately = mFdp.ConsumeIntegral<bool>()});
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index 1d0f62b..a80aca2 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -22,6 +22,7 @@
#include <compositionengine/impl/CompositionEngine.h>
#include <compositionengine/impl/Display.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
+#include <ftl/fake_guard.h>
#include <gui/LayerDebugInfo.h>
#include <gui/ScreenCaptureResults.h>
#include <gui/SurfaceComposerClient.h>
@@ -50,6 +51,7 @@
#include "SurfaceFlinger.h"
#include "SurfaceFlingerDefaultFactory.h"
#include "SurfaceInterceptor.h"
+#include "ThreadContext.h"
#include "TimeStats/TimeStats.h"
#include "renderengine/mock/RenderEngine.h"
@@ -445,7 +447,7 @@
mFlinger->clearStatsLocked(dumpArgs, result);
mFlinger->dumpTimeStats(dumpArgs, fdp->ConsumeBool(), result);
- mFlinger->logFrameStats();
+ FTL_FAKE_GUARD(kMainThreadContext, mFlinger->logFrameStats());
result = fdp->ConsumeRandomLengthString().c_str();
mFlinger->dumpFrameTimeline(dumpArgs, result);
@@ -651,7 +653,7 @@
updateCompositorTiming(&mFdp);
mFlinger->setCompositorTimingSnapped({}, mFdp.ConsumeIntegral<nsecs_t>());
- mFlinger->postFrame();
+ FTL_FAKE_GUARD(kMainThreadContext, mFlinger->postFrame());
mFlinger->calculateExpectedPresentTime({});
mFlinger->enableHalVirtualDisplays(mFdp.ConsumeBool());
diff --git a/services/surfaceflinger/tests/BootDisplayMode_test.cpp b/services/surfaceflinger/tests/BootDisplayMode_test.cpp
index abdb16d..d70908e 100644
--- a/services/surfaceflinger/tests/BootDisplayMode_test.cpp
+++ b/services/surfaceflinger/tests/BootDisplayMode_test.cpp
@@ -20,28 +20,33 @@
#include <gui/SurfaceComposerClient.h>
#include <private/gui/ComposerService.h>
+#include <private/gui/ComposerServiceAIDL.h>
#include <chrono>
namespace android {
TEST(BootDisplayModeTest, setBootDisplayMode) {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ sp<gui::ISurfaceComposer> sf_aidl(ComposerServiceAIDL::getComposerService());
auto displayToken = SurfaceComposerClient::getInternalDisplayToken();
bool bootModeSupport = false;
- ASSERT_NO_FATAL_FAILURE(sf->getBootDisplayModeSupport(&bootModeSupport));
+ binder::Status status = sf_aidl->getBootDisplayModeSupport(&bootModeSupport);
+ ASSERT_NO_FATAL_FAILURE(status.transactionError());
if (bootModeSupport) {
ASSERT_EQ(NO_ERROR, sf->setBootDisplayMode(displayToken, 0));
}
}
TEST(BootDisplayModeTest, clearBootDisplayMode) {
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService());
auto displayToken = SurfaceComposerClient::getInternalDisplayToken();
bool bootModeSupport = false;
- ASSERT_NO_FATAL_FAILURE(sf->getBootDisplayModeSupport(&bootModeSupport));
+ binder::Status status = sf->getBootDisplayModeSupport(&bootModeSupport);
+ ASSERT_NO_FATAL_FAILURE(status.transactionError());
if (bootModeSupport) {
- ASSERT_EQ(NO_ERROR, sf->clearBootDisplayMode(displayToken));
+ status = sf->clearBootDisplayMode(displayToken);
+ ASSERT_EQ(NO_ERROR, status.transactionError());
}
}
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp
index 8a2305b..219db8c 100644
--- a/services/surfaceflinger/tests/LayerCallback_test.cpp
+++ b/services/surfaceflinger/tests/LayerCallback_test.cpp
@@ -55,24 +55,34 @@
return createLayer(mClient, "test", 0, 0, ISurfaceComposerClient::eFXSurfaceBufferState);
}
+ static int fillBuffer(Transaction& transaction, const sp<SurfaceControl>& layer,
+ bool setBuffer = true, bool setBackgroundColor = false) {
+ sp<GraphicBuffer> buffer;
+ sp<Fence> fence;
+ if (setBuffer) {
+ int err = getBuffer(&buffer, &fence);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ transaction.setBuffer(layer, buffer, fence);
+ }
+
+ if (setBackgroundColor) {
+ transaction.setBackgroundColor(layer, /*color*/ half3(1.0f, 0, 0), /*alpha*/ 1.0f,
+ ui::Dataspace::UNKNOWN);
+ }
+
+ return NO_ERROR;
+ }
+
static int fillTransaction(Transaction& transaction, CallbackHelper* callbackHelper,
const sp<SurfaceControl>& layer = nullptr, bool setBuffer = true,
bool setBackgroundColor = false) {
if (layer) {
- sp<GraphicBuffer> buffer;
- sp<Fence> fence;
- if (setBuffer) {
- int err = getBuffer(&buffer, &fence);
- if (err != NO_ERROR) {
- return err;
- }
-
- transaction.setBuffer(layer, buffer, fence);
- }
-
- if (setBackgroundColor) {
- transaction.setBackgroundColor(layer, /*color*/ half3(1.0f, 0, 0), /*alpha*/ 1.0f,
- ui::Dataspace::UNKNOWN);
+ int err = fillBuffer(transaction, layer, setBuffer, setBackgroundColor);
+ if (err != NO_ERROR) {
+ return err;
}
}
@@ -1115,7 +1125,7 @@
Transaction transaction;
CallbackHelper callback;
int err = fillTransaction(transaction, &callback, layer, true);
- err |= fillTransaction(transaction, &callback, offscreenLayer, true);
+ err |= fillBuffer(transaction, offscreenLayer);
if (err) {
GTEST_SUCCEED() << "test not supported";
return;
@@ -1129,5 +1139,86 @@
committedSc.insert(layer);
committedSc.insert(offscreenLayer);
EXPECT_NO_FATAL_FAILURE(waitForCommitCallback(callback, committedSc));
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, offscreenLayer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
}
+
+TEST_F(LayerCallbackTest, TransactionCommittedCallback_BSL) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback, layer, true);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ transaction.addTransactionCommittedCallback(callback.function, callback.getContext()).apply();
+ std::unordered_set<sp<SurfaceControl>, SCHash> committedSc;
+ committedSc.insert(layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCommitCallback(callback, committedSc));
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, TransactionCommittedCallback_EffectLayer) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createColorLayer("ColorLayer", Color::RED));
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ transaction.addTransactionCommittedCallback(callback.function, callback.getContext()).apply();
+ std::unordered_set<sp<SurfaceControl>, SCHash> committedSc;
+ EXPECT_NO_FATAL_FAILURE(waitForCommitCallback(callback, committedSc));
+
+ ExpectedResult expected;
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, TransactionCommittedCallback_ContainerLayer) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer(mClient, "Container Layer", 0, 0,
+ ISurfaceComposerClient::eFXSurfaceContainer));
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ transaction.addTransactionCommittedCallback(callback.function, callback.getContext()).apply();
+ std::unordered_set<sp<SurfaceControl>, SCHash> committedSc;
+ EXPECT_NO_FATAL_FAILURE(waitForCommitCallback(callback, committedSc));
+
+ ExpectedResult expected;
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, TransactionCommittedCallback_NoLayer) {
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ transaction.addTransactionCommittedCallback(callback.function, callback.getContext()).apply();
+ std::unordered_set<sp<SurfaceControl>, SCHash> committedSc;
+ EXPECT_NO_FATAL_FAILURE(waitForCommitCallback(callback, committedSc));
+
+ ExpectedResult expected;
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
} // namespace android
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
index 168b576..704815d 100644
--- a/services/surfaceflinger/tests/fakehwc/Android.bp
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -28,6 +28,7 @@
"android.hardware.graphics.mapper@3.0",
"android.hardware.graphics.mapper@4.0",
"android.hardware.power@1.3",
+ "android.hardware.power-V2-cpp",
"libbase",
"libbinder",
"libbinder_ndk",
diff --git a/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp b/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp
new file mode 100644
index 0000000..9ab35d7
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp
@@ -0,0 +1,310 @@
+/*
+ * 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 "AidlPowerHalWrapperTest"
+
+#include <android-base/stringprintf.h>
+#include <android/hardware/power/IPower.h>
+#include <android/hardware/power/IPowerHintSession.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <algorithm>
+#include <chrono>
+#include <memory>
+#include "DisplayHardware/PowerAdvisor.h"
+#include "android/hardware/power/WorkDuration.h"
+#include "binder/Status.h"
+#include "log/log_main.h"
+#include "mock/DisplayHardware/MockIPower.h"
+#include "mock/DisplayHardware/MockIPowerHintSession.h"
+#include "utils/Timers.h"
+
+using namespace android;
+using namespace android::Hwc2::mock;
+using namespace android::hardware::power;
+using namespace std::chrono_literals;
+using namespace testing;
+
+namespace android::Hwc2::impl {
+
+class AidlPowerHalWrapperTest : public testing::Test {
+public:
+ void SetUp() override;
+
+protected:
+ std::unique_ptr<AidlPowerHalWrapper> mWrapper = nullptr;
+ sp<NiceMock<MockIPower>> mMockHal = nullptr;
+ sp<NiceMock<MockIPowerHintSession>> mMockSession = nullptr;
+ void verifyAndClearExpectations();
+ void sendActualWorkDurationGroup(std::vector<WorkDuration> durations,
+ std::chrono::nanoseconds sleepBeforeLastSend);
+};
+
+void AidlPowerHalWrapperTest::SetUp() {
+ mMockHal = new NiceMock<MockIPower>();
+ mMockSession = new NiceMock<MockIPowerHintSession>();
+ ON_CALL(*mMockHal.get(), getHintSessionPreferredRate(_)).WillByDefault(Return(Status::ok()));
+ mWrapper = std::make_unique<AidlPowerHalWrapper>(mMockHal);
+}
+
+void AidlPowerHalWrapperTest::verifyAndClearExpectations() {
+ Mock::VerifyAndClearExpectations(mMockHal.get());
+ Mock::VerifyAndClearExpectations(mMockSession.get());
+}
+
+void AidlPowerHalWrapperTest::sendActualWorkDurationGroup(
+ std::vector<WorkDuration> durations, std::chrono::nanoseconds sleepBeforeLastSend) {
+ for (size_t i = 0; i < durations.size(); i++) {
+ if (i == durations.size() - 1) {
+ std::this_thread::sleep_for(sleepBeforeLastSend);
+ }
+ auto duration = durations[i];
+ mWrapper->sendActualWorkDuration(duration.durationNanos, duration.timeStampNanos);
+ }
+}
+WorkDuration toWorkDuration(std::chrono::nanoseconds durationNanos, int64_t timeStampNanos) {
+ WorkDuration duration;
+ duration.durationNanos = durationNanos.count();
+ duration.timeStampNanos = timeStampNanos;
+ return duration;
+}
+
+std::string printWorkDurations(const ::std::vector<WorkDuration>& durations) {
+ std::ostringstream os;
+ for (auto duration : durations) {
+ os << duration.toString();
+ os << "\n";
+ }
+ return os.str();
+}
+
+namespace {
+TEST_F(AidlPowerHalWrapperTest, supportsPowerHintSession) {
+ ASSERT_TRUE(mWrapper->supportsPowerHintSession());
+ Mock::VerifyAndClearExpectations(mMockHal.get());
+ ON_CALL(*mMockHal.get(), getHintSessionPreferredRate(_))
+ .WillByDefault(Return(Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE)));
+ auto newWrapper = AidlPowerHalWrapper(mMockHal);
+ EXPECT_FALSE(newWrapper.supportsPowerHintSession());
+}
+
+TEST_F(AidlPowerHalWrapperTest, startPowerHintSession) {
+ ASSERT_TRUE(mWrapper->supportsPowerHintSession());
+ std::vector<int32_t> threadIds = {1, 2};
+ mWrapper->setPowerHintSessionThreadIds(threadIds);
+ EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
+ .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
+ EXPECT_TRUE(mWrapper->startPowerHintSession());
+ EXPECT_FALSE(mWrapper->startPowerHintSession());
+}
+
+TEST_F(AidlPowerHalWrapperTest, restartNewPoserHintSessionWithNewThreadIds) {
+ ASSERT_TRUE(mWrapper->supportsPowerHintSession());
+
+ std::vector<int32_t> threadIds = {1, 2};
+ EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
+ .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
+ mWrapper->setPowerHintSessionThreadIds(threadIds);
+ EXPECT_EQ(mWrapper->getPowerHintSessionThreadIds(), threadIds);
+ ASSERT_TRUE(mWrapper->startPowerHintSession());
+ verifyAndClearExpectations();
+
+ threadIds = {2, 3};
+ EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
+ .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
+ EXPECT_CALL(*mMockSession.get(), close()).Times(1);
+ mWrapper->setPowerHintSessionThreadIds(threadIds);
+ EXPECT_EQ(mWrapper->getPowerHintSessionThreadIds(), threadIds);
+ verifyAndClearExpectations();
+
+ EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _)).Times(0);
+ EXPECT_CALL(*mMockSession.get(), close()).Times(0);
+ mWrapper->setPowerHintSessionThreadIds(threadIds);
+ verifyAndClearExpectations();
+}
+
+TEST_F(AidlPowerHalWrapperTest, setTargetWorkDuration) {
+ ASSERT_TRUE(mWrapper->supportsPowerHintSession());
+
+ std::vector<int32_t> threadIds = {1, 2};
+ mWrapper->setPowerHintSessionThreadIds(threadIds);
+ EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
+ .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
+ ASSERT_TRUE(mWrapper->startPowerHintSession());
+ verifyAndClearExpectations();
+
+ std::chrono::nanoseconds base = 100ms;
+ // test cases with target work duration and whether it should update hint against baseline 100ms
+ const std::vector<std::pair<std::chrono::nanoseconds, bool>> testCases = {{0ms, false},
+ {-1ms, false},
+ {200ms, true},
+ {2ms, true},
+ {91ms, false},
+ {109ms, false}};
+
+ for (const auto& test : testCases) {
+ // reset to 100ms baseline
+ mWrapper->setTargetWorkDuration(1);
+ mWrapper->setTargetWorkDuration(base.count());
+
+ auto target = test.first;
+ EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(target.count()))
+ .Times(test.second ? 1 : 0);
+ mWrapper->setTargetWorkDuration(target.count());
+ verifyAndClearExpectations();
+ }
+}
+
+TEST_F(AidlPowerHalWrapperTest, setTargetWorkDuration_shouldReconnectOnError) {
+ ASSERT_TRUE(mWrapper->supportsPowerHintSession());
+
+ std::vector<int32_t> threadIds = {1, 2};
+ mWrapper->setPowerHintSessionThreadIds(threadIds);
+ EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
+ .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
+ ASSERT_TRUE(mWrapper->startPowerHintSession());
+ verifyAndClearExpectations();
+
+ EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(1))
+ .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE)));
+ mWrapper->setTargetWorkDuration(1);
+ EXPECT_TRUE(mWrapper->shouldReconnectHAL());
+}
+
+TEST_F(AidlPowerHalWrapperTest, sendActualWorkDuration) {
+ ASSERT_TRUE(mWrapper->supportsPowerHintSession());
+
+ std::vector<int32_t> threadIds = {1, 2};
+ mWrapper->setPowerHintSessionThreadIds(threadIds);
+ EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
+ .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
+ ASSERT_TRUE(mWrapper->startPowerHintSession());
+ verifyAndClearExpectations();
+
+ auto base = toWorkDuration(100ms, 0);
+ // test cases with actual work durations and whether it should update hint against baseline
+ // 100ms
+ const std::vector<std::pair<std::vector<std::pair<std::chrono::nanoseconds, nsecs_t>>, bool>>
+ testCases = {{{{-1ms, 100}}, false},
+ {{{91ms, 100}}, false},
+ {{{109ms, 100}}, false},
+ {{{100ms, 100}, {200ms, 200}}, true},
+ {{{100ms, 500}, {100ms, 600}, {3ms, 600}}, true}};
+
+ for (const auto& test : testCases) {
+ // reset actual duration
+ sendActualWorkDurationGroup({base}, 80ms);
+
+ auto raw = test.first;
+ std::vector<WorkDuration> durations(raw.size());
+ std::transform(raw.begin(), raw.end(), durations.begin(),
+ [](std::pair<std::chrono::nanoseconds, nsecs_t> d) {
+ return toWorkDuration(d.first, d.second);
+ });
+ EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(durations))
+ .Times(test.second ? 1 : 0);
+ sendActualWorkDurationGroup(durations, 0ms);
+ verifyAndClearExpectations();
+ }
+}
+
+TEST_F(AidlPowerHalWrapperTest, sendAdjustedActualWorkDuration) {
+ ASSERT_TRUE(mWrapper->supportsPowerHintSession());
+
+ std::vector<int32_t> threadIds = {1, 2};
+ mWrapper->setPowerHintSessionThreadIds(threadIds);
+ EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
+ .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
+ ASSERT_TRUE(mWrapper->startPowerHintSession());
+ verifyAndClearExpectations();
+
+ std::chrono::nanoseconds lastTarget = 100ms;
+ EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(lastTarget.count())).Times(1);
+ mWrapper->setTargetWorkDuration(lastTarget.count());
+ std::chrono::nanoseconds newTarget = 105ms;
+ mWrapper->setTargetWorkDuration(newTarget.count());
+ EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(newTarget.count())).Times(0);
+ std::chrono::nanoseconds actual = 21ms;
+ // 100 / 105 * 21ms = 20ms
+ std::chrono::nanoseconds expectedActualSent = 20ms;
+ std::vector<WorkDuration> expectedDurations = {toWorkDuration(expectedActualSent, 1)};
+
+ EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(_))
+ .WillOnce(DoAll(
+ [expectedDurations](const ::std::vector<WorkDuration>& durationsSent) {
+ EXPECT_EQ(expectedDurations, durationsSent)
+ << base::StringPrintf("actual sent: %s vs expected: %s",
+ printWorkDurations(durationsSent).c_str(),
+ printWorkDurations(expectedDurations)
+ .c_str());
+ },
+ Return(Status::ok())));
+ mWrapper->sendActualWorkDuration(actual.count(), 1);
+}
+
+TEST_F(AidlPowerHalWrapperTest, sendActualWorkDuration_exceedsStaleTime) {
+ ASSERT_TRUE(mWrapper->supportsPowerHintSession());
+
+ std::vector<int32_t> threadIds = {1, 2};
+ mWrapper->setPowerHintSessionThreadIds(threadIds);
+ EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
+ .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
+ ASSERT_TRUE(mWrapper->startPowerHintSession());
+ verifyAndClearExpectations();
+
+ auto base = toWorkDuration(100ms, 0);
+ // test cases with actual work durations and whether it should update hint against baseline
+ // 100ms
+ const std::vector<std::pair<std::vector<std::pair<std::chrono::nanoseconds, nsecs_t>>, bool>>
+ testCases = {{{{91ms, 100}}, true}, {{{109ms, 100}}, true}};
+
+ for (const auto& test : testCases) {
+ // reset actual duration
+ sendActualWorkDurationGroup({base}, 80ms);
+
+ auto raw = test.first;
+ std::vector<WorkDuration> durations(raw.size());
+ std::transform(raw.begin(), raw.end(), durations.begin(),
+ [](std::pair<std::chrono::nanoseconds, nsecs_t> d) {
+ return toWorkDuration(d.first, d.second);
+ });
+ EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(durations))
+ .Times(test.second ? 1 : 0);
+ sendActualWorkDurationGroup(durations, 80ms);
+ verifyAndClearExpectations();
+ }
+}
+
+TEST_F(AidlPowerHalWrapperTest, sendActualWorkDuration_shouldReconnectOnError) {
+ ASSERT_TRUE(mWrapper->supportsPowerHintSession());
+
+ std::vector<int32_t> threadIds = {1, 2};
+ mWrapper->setPowerHintSessionThreadIds(threadIds);
+ EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
+ .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
+ ASSERT_TRUE(mWrapper->startPowerHintSession());
+ verifyAndClearExpectations();
+ WorkDuration duration;
+ duration.durationNanos = 1;
+ EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(_))
+ .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE)));
+ sendActualWorkDurationGroup({duration}, 0ms);
+ EXPECT_TRUE(mWrapper->shouldReconnectHAL());
+}
+
+} // namespace
+} // namespace android::Hwc2::impl
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 1eea023..7823363 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -26,6 +26,8 @@
srcs: [
"mock/DisplayHardware/MockComposer.cpp",
"mock/DisplayHardware/MockHWC2.cpp",
+ "mock/DisplayHardware/MockIPower.cpp",
+ "mock/DisplayHardware/MockIPowerHintSession.cpp",
"mock/DisplayHardware/MockPowerAdvisor.cpp",
"mock/MockEventThread.cpp",
"mock/MockFrameTimeline.cpp",
@@ -67,6 +69,7 @@
":libsurfaceflinger_mock_sources",
":libsurfaceflinger_sources",
"libsurfaceflinger_unittest_main.cpp",
+ "AidlPowerHalWrapperTest.cpp",
"CachingTest.cpp",
"CompositionTest.cpp",
"DispSyncSourceTest.cpp",
@@ -100,6 +103,7 @@
"SurfaceFlinger_HotplugTest.cpp",
"SurfaceFlinger_NotifyPowerBoostTest.cpp",
"SurfaceFlinger_OnInitializeDisplaysTest.cpp",
+ "SurfaceFlinger_PowerHintTest.cpp",
"SurfaceFlinger_SetDisplayStateTest.cpp",
"SurfaceFlinger_SetPowerModeInternalTest.cpp",
"SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 15c9d19..c541b92 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -113,8 +113,9 @@
mFlinger.setupTimeStats(std::shared_ptr<TimeStats>(mTimeStats));
mComposer = new Hwc2::mock::Composer();
+ mPowerAdvisor = new Hwc2::mock::PowerAdvisor();
mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
-
+ mFlinger.setupPowerAdvisor(std::unique_ptr<Hwc2::PowerAdvisor>(mPowerAdvisor));
mFlinger.mutableMaxRenderTargetSize() = 16384;
}
@@ -188,7 +189,7 @@
Hwc2::mock::Composer* mComposer = nullptr;
renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
mock::TimeStats* mTimeStats = new mock::TimeStats();
- Hwc2::mock::PowerAdvisor mPowerAdvisor;
+ Hwc2::mock::PowerAdvisor* mPowerAdvisor = nullptr;
sp<Fence> mClientTargetAcquireFence = Fence::NO_FENCE;
@@ -300,7 +301,7 @@
.setId(DEFAULT_DISPLAY_ID)
.setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT})
.setIsSecure(Derived::IS_SECURE)
- .setPowerAdvisor(&test->mPowerAdvisor)
+ .setPowerAdvisor(test->mPowerAdvisor)
.setName(std::string("Injected display for ") +
test_info->test_case_name() + "." + test_info->name())
.build();
diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp
index 73c60e1..225ad16 100644
--- a/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp
@@ -19,6 +19,7 @@
#include "DisplayTransactionTestHelpers.h"
+#include <ftl/fake_guard.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -35,7 +36,7 @@
};
TEST_F(SetDisplayBrightnessTest, persistDisplayBrightnessNoComposite) {
- MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD);
+ ftl::FakeGuard guard(kMainThreadContext);
sp<DisplayDevice> displayDevice = getDisplayDevice();
EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
@@ -52,7 +53,7 @@
}
TEST_F(SetDisplayBrightnessTest, persistDisplayBrightnessWithComposite) {
- MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD);
+ ftl::FakeGuard guard(kMainThreadContext);
sp<DisplayDevice> displayDevice = getDisplayDevice();
EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
@@ -70,7 +71,7 @@
}
TEST_F(SetDisplayBrightnessTest, persistDisplayBrightnessWithCompositeShortCircuitsOnNoOp) {
- MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD);
+ ftl::FakeGuard guard(kMainThreadContext);
sp<DisplayDevice> displayDevice = getDisplayDevice();
EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_SetProjectionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_SetProjectionTest.cpp
index 3d24ecb..5734d34 100644
--- a/services/surfaceflinger/tests/unittests/DisplayDevice_SetProjectionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayDevice_SetProjectionTest.cpp
@@ -21,6 +21,7 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <ui/Rotation.h>
namespace android {
namespace {
@@ -53,6 +54,11 @@
ui::Size swapWH(const ui::Size size) const { return ui::Size(size.height, size.width); }
+ void setDefaultProjection() {
+ // INVALID_RECT pulls from the physical display dimensions.
+ mDisplayDevice->setProjection(ui::ROTATION_0, Rect::INVALID_RECT, Rect::INVALID_RECT);
+ }
+
void setProjectionForRotation0() {
// A logical rotation of 0 uses the SurfaceFlinger display size
mDisplayDevice->setProjection(ui::ROTATION_0, Rect(mFlingerDisplaySize),
@@ -79,6 +85,30 @@
Rect(swapWH(mFlingerDisplaySize)));
}
+ void expectDefaultState() {
+ const auto& compositionState = mDisplayDevice->getCompositionDisplay()->getState();
+ EXPECT_EQ(ui::Transform(ui::Transform::toRotationFlags(mPhysicalOrientation),
+ mHardwareDisplaySize.width, mHardwareDisplaySize.height),
+ compositionState.transform);
+ EXPECT_EQ(mPhysicalOrientation, compositionState.displaySpace.getOrientation());
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.getContent());
+ EXPECT_EQ(mHardwareDisplaySize, compositionState.displaySpace.getBounds());
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.framebufferSpace.getContent());
+ EXPECT_EQ(mHardwareDisplaySize, compositionState.framebufferSpace.getBounds());
+
+ const ui::Size expectedLogicalSize = (mPhysicalOrientation == ui::ROTATION_270 ||
+ mPhysicalOrientation == ui::ROTATION_90)
+ ? swapWH(mHardwareDisplaySize)
+ : mHardwareDisplaySize;
+
+ EXPECT_EQ(Rect(expectedLogicalSize), compositionState.orientedDisplaySpace.getContent());
+ EXPECT_EQ(expectedLogicalSize, compositionState.orientedDisplaySpace.getBounds());
+ EXPECT_EQ(Rect(expectedLogicalSize), compositionState.layerStackSpace.getContent());
+ EXPECT_EQ(expectedLogicalSize, compositionState.layerStackSpace.getBounds());
+
+ EXPECT_EQ(false, compositionState.needsFiltering);
+ }
+
void expectStateForHardwareTransform0() {
const auto& compositionState = mDisplayDevice->getCompositionDisplay()->getState();
EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_0, mHardwareDisplaySize.width,
@@ -147,6 +177,11 @@
ui::ROTATION_0) {}
};
+TEST_F(DisplayDeviceSetProjectionTest_Installed0, checkDefaultProjection) {
+ setDefaultProjection();
+ expectDefaultState();
+}
+
TEST_F(DisplayDeviceSetProjectionTest_Installed0, checkWith0OutputRotation) {
setProjectionForRotation0();
expectStateForHardwareTransform0();
@@ -174,6 +209,11 @@
ui::ROTATION_90) {}
};
+TEST_F(DisplayDeviceSetProjectionTest_Installed90, checkDefaultProjection) {
+ setDefaultProjection();
+ expectDefaultState();
+}
+
TEST_F(DisplayDeviceSetProjectionTest_Installed90, checkWith0OutputRotation) {
setProjectionForRotation0();
expectStateForHardwareTransform90();
@@ -201,6 +241,11 @@
ui::ROTATION_180) {}
};
+TEST_F(DisplayDeviceSetProjectionTest_Installed180, checkDefaultProjection) {
+ setDefaultProjection();
+ expectDefaultState();
+}
+
TEST_F(DisplayDeviceSetProjectionTest_Installed180, checkWith0OutputRotation) {
setProjectionForRotation0();
expectStateForHardwareTransform180();
@@ -228,6 +273,11 @@
ui::ROTATION_270) {}
};
+TEST_F(DisplayDeviceSetProjectionTest_Installed270, checkDefaultProjection) {
+ setDefaultProjection();
+ expectDefaultState();
+}
+
TEST_F(DisplayDeviceSetProjectionTest_Installed270, checkWith0OutputRotation) {
setProjectionForRotation0();
expectStateForHardwareTransform270();
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 2425862..f04221c 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -165,36 +165,39 @@
return displayDevice;
}
-bool DisplayTransactionTest::hasPhysicalHwcDisplay(HWDisplayId hwcDisplayId) {
- return mFlinger.mutableHwcPhysicalDisplayIdMap().count(hwcDisplayId) == 1;
+bool DisplayTransactionTest::hasPhysicalHwcDisplay(HWDisplayId hwcDisplayId) const {
+ return mFlinger.hwcPhysicalDisplayIdMap().count(hwcDisplayId) == 1;
}
-bool DisplayTransactionTest::hasTransactionFlagSet(int flag) {
- return mFlinger.mutableTransactionFlags() & flag;
+bool DisplayTransactionTest::hasTransactionFlagSet(int32_t flag) const {
+ return mFlinger.transactionFlags() & flag;
}
-bool DisplayTransactionTest::hasDisplayDevice(sp<IBinder> displayToken) {
- return mFlinger.mutableDisplays().count(displayToken) == 1;
+bool DisplayTransactionTest::hasDisplayDevice(const sp<IBinder>& displayToken) const {
+ return mFlinger.displays().contains(displayToken);
}
-sp<DisplayDevice> DisplayTransactionTest::getDisplayDevice(sp<IBinder> displayToken) {
- return mFlinger.mutableDisplays()[displayToken];
+const DisplayDevice& DisplayTransactionTest::getDisplayDevice(
+ const sp<IBinder>& displayToken) const {
+ return *mFlinger.displays().get(displayToken)->get();
}
-bool DisplayTransactionTest::hasCurrentDisplayState(sp<IBinder> displayToken) {
- return mFlinger.mutableCurrentState().displays.indexOfKey(displayToken) >= 0;
+bool DisplayTransactionTest::hasCurrentDisplayState(const sp<IBinder>& displayToken) const {
+ return mFlinger.currentState().displays.indexOfKey(displayToken) >= 0;
}
-const DisplayDeviceState& DisplayTransactionTest::getCurrentDisplayState(sp<IBinder> displayToken) {
- return mFlinger.mutableCurrentState().displays.valueFor(displayToken);
+const DisplayDeviceState& DisplayTransactionTest::getCurrentDisplayState(
+ const sp<IBinder>& displayToken) const {
+ return mFlinger.currentState().displays.valueFor(displayToken);
}
-bool DisplayTransactionTest::hasDrawingDisplayState(sp<IBinder> displayToken) {
- return mFlinger.mutableDrawingState().displays.indexOfKey(displayToken) >= 0;
+bool DisplayTransactionTest::hasDrawingDisplayState(const sp<IBinder>& displayToken) const {
+ return mFlinger.drawingState().displays.indexOfKey(displayToken) >= 0;
}
-const DisplayDeviceState& DisplayTransactionTest::getDrawingDisplayState(sp<IBinder> displayToken) {
- return mFlinger.mutableDrawingState().displays.valueFor(displayToken);
+const DisplayDeviceState& DisplayTransactionTest::getDrawingDisplayState(
+ const sp<IBinder>& displayToken) const {
+ return mFlinger.drawingState().displays.valueFor(displayToken);
}
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index 565c244..f5235ce 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -95,14 +95,17 @@
// --------------------------------------------------------------------
// Postcondition helpers
- bool hasPhysicalHwcDisplay(hal::HWDisplayId hwcDisplayId);
- bool hasTransactionFlagSet(int flag);
- bool hasDisplayDevice(sp<IBinder> displayToken);
- sp<DisplayDevice> getDisplayDevice(sp<IBinder> displayToken);
- bool hasCurrentDisplayState(sp<IBinder> displayToken);
- const DisplayDeviceState& getCurrentDisplayState(sp<IBinder> displayToken);
- bool hasDrawingDisplayState(sp<IBinder> displayToken);
- const DisplayDeviceState& getDrawingDisplayState(sp<IBinder> displayToken);
+ bool hasPhysicalHwcDisplay(hal::HWDisplayId) const;
+ bool hasTransactionFlagSet(int32_t flag) const;
+
+ bool hasDisplayDevice(const sp<IBinder>& displayToken) const;
+ const DisplayDevice& getDisplayDevice(const sp<IBinder>& displayToken) const;
+
+ bool hasCurrentDisplayState(const sp<IBinder>& displayToken) const;
+ const DisplayDeviceState& getCurrentDisplayState(const sp<IBinder>& displayToken) const;
+
+ bool hasDrawingDisplayState(const sp<IBinder>& displayToken) const;
+ const DisplayDeviceState& getDrawingDisplayState(const sp<IBinder>& displayToken) const;
// --------------------------------------------------------------------
// Test instances
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 14d8f98..c033af8 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -34,12 +34,13 @@
using namespace std::chrono_literals;
using namespace std::placeholders;
-using namespace android::flag_operators;
using testing::_;
using testing::Invoke;
namespace android {
+using namespace ftl::flag_operators;
+
namespace {
constexpr PhysicalDisplayId INTERNAL_DISPLAY_ID = PhysicalDisplayId::fromPort(111u);
@@ -414,6 +415,10 @@
EXPECT_CALL(*mVSyncSource, getLatestVSyncData()).WillOnce(Return(preferredData));
VsyncEventData vsyncEventData = mThread->getLatestVsyncEventData(mConnection);
+
+ // Check EventThread immediately requested a resync.
+ EXPECT_TRUE(mResyncCallRecorder.waitForCall().has_value());
+
EXPECT_GT(vsyncEventData.frameTimelines[0].deadlineTimestamp, now)
<< "Deadline timestamp should be greater than frame time";
for (size_t i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
index 825f145..b9a5f36 100644
--- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
@@ -337,10 +337,22 @@
ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS, ""));
EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
+
+ // Privileged APIs.
+ EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
+ EXPECT_FALSE(ValidateFrameRate(0.0f, ANATIVEWINDOW_FRAME_RATE_NO_VOTE,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
+
+ constexpr bool kPrivileged = true;
EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT,
ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "",
- /*privileged=*/true));
+ kPrivileged));
+ EXPECT_TRUE(ValidateFrameRate(0.0f, ANATIVEWINDOW_FRAME_RATE_NO_VOTE,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "",
+ kPrivileged));
+ // Invalid frame rate.
EXPECT_FALSE(ValidateFrameRate(-1, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
EXPECT_FALSE(ValidateFrameRate(1.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
@@ -348,15 +360,12 @@
EXPECT_FALSE(ValidateFrameRate(0.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
- EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT,
- ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
-
- // Invalid compatibility
+ // Invalid compatibility.
EXPECT_FALSE(
ValidateFrameRate(60.0f, -1, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
EXPECT_FALSE(ValidateFrameRate(60.0f, 2, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
- // Invalid change frame rate strategy
+ // Invalid change frame rate strategy.
EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, -1, ""));
EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, 2, ""));
}
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
index 32d57b5..5872a47 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
@@ -61,7 +61,6 @@
protected:
void setupScheduler(std::shared_ptr<scheduler::RefreshRateConfigs>);
- void testChangeRefreshRate(bool isDisplayActive, bool isRefreshRequired);
sp<DisplayDevice> mDisplay;
mock::EventThread* mAppEventThread;
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp
index 6959ee3..9ac2907 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp
@@ -107,9 +107,10 @@
void DisplayTransactionCommitTest::verifyDisplayIsConnected(const sp<IBinder>& displayToken) {
// The display device should have been set up in the list of displays.
ASSERT_TRUE(hasDisplayDevice(displayToken));
- const auto& device = getDisplayDevice(displayToken);
- EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure());
- EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary());
+ const auto& display = getDisplayDevice(displayToken);
+
+ EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), display.isSecure());
+ EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), display.isPrimary());
std::optional<DisplayDeviceState::Physical> expectedPhysical;
if (const auto connectionType = Case::Display::CONNECTION_TYPE::value) {
@@ -143,10 +144,11 @@
// SF should have a display token.
const auto displayId = Case::Display::DISPLAY_ID::get();
ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
- ASSERT_EQ(mFlinger.mutablePhysicalDisplayTokens().count(displayId), 1);
- auto& displayToken = mFlinger.mutablePhysicalDisplayTokens()[displayId];
- verifyDisplayIsConnected<Case>(displayToken);
+ const auto displayTokenOpt = mFlinger.mutablePhysicalDisplayTokens().get(displayId);
+ ASSERT_TRUE(displayTokenOpt);
+
+ verifyDisplayIsConnected<Case>(displayTokenOpt->get());
}
void DisplayTransactionCommitTest::verifyDisplayIsNotConnected(const sp<IBinder>& displayToken) {
@@ -248,9 +250,9 @@
// SF should not have a display token.
const auto displayId = Case::Display::DISPLAY_ID::get();
ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
- ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 0);
+ ASSERT_FALSE(mFlinger.mutablePhysicalDisplayTokens().contains(displayId));
- // The existing token should have been removed
+ // The existing token should have been removed.
verifyDisplayIsNotConnected(existing.token());
}
@@ -330,7 +332,7 @@
// SF should not have a display token.
const auto displayId = Case::Display::DISPLAY_ID::get();
ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
- ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 0);
+ ASSERT_FALSE(mFlinger.mutablePhysicalDisplayTokens().contains(displayId));
}(),
testing::KilledBySignal(SIGABRT), "Primary display cannot be disconnected.");
}
@@ -369,15 +371,16 @@
// --------------------------------------------------------------------
// Postconditions
- // The existing token should have been removed
+ // The existing token should have been removed.
verifyDisplayIsNotConnected(existing.token());
const auto displayId = Case::Display::DISPLAY_ID::get();
ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
- ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 1);
- EXPECT_NE(existing.token(), mFlinger.mutablePhysicalDisplayTokens()[displayId]);
- // A new display should be connected in its place
+ const auto displayTokenOpt = mFlinger.mutablePhysicalDisplayTokens().get(displayId);
+ ASSERT_TRUE(displayTokenOpt);
+ EXPECT_NE(existing.token(), displayTokenOpt->get());
+ // A new display should be connected in its place.
verifyPhysicalDisplayIsConnected<Case>();
// --------------------------------------------------------------------
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
new file mode 100644
index 0000000..8de9e4b
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
@@ -0,0 +1,154 @@
+/*
+ * 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 "SurfaceFlingerPowerHintTest"
+
+#include <compositionengine/Display.h>
+#include <compositionengine/mock/DisplaySurface.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <renderengine/mock/RenderEngine.h>
+#include <algorithm>
+#include <chrono>
+#include <memory>
+#include "TestableSurfaceFlinger.h"
+#include "mock/DisplayHardware/MockComposer.h"
+#include "mock/DisplayHardware/MockPowerAdvisor.h"
+#include "mock/MockEventThread.h"
+#include "mock/MockTimeStats.h"
+#include "mock/MockVsyncController.h"
+#include "mock/system/window/MockNativeWindow.h"
+
+using namespace android;
+using namespace android::Hwc2::mock;
+using namespace android::hardware::power;
+using namespace std::chrono_literals;
+using namespace testing;
+
+namespace android {
+namespace {
+using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
+
+constexpr hal::HWDisplayId HWC_DISPLAY = FakeHwcDisplayInjector::DEFAULT_HWC_DISPLAY_ID;
+constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(42u);
+constexpr int DEFAULT_DISPLAY_WIDTH = 1920;
+constexpr int DEFAULT_DISPLAY_HEIGHT = 1024;
+
+class SurfaceFlingerPowerHintTest : public Test {
+public:
+ void SetUp() override;
+
+ void setupScheduler();
+
+protected:
+ TestableSurfaceFlinger mFlinger;
+ renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
+ sp<DisplayDevice> mDisplay;
+ sp<compositionengine::mock::DisplaySurface> mDisplaySurface =
+ new compositionengine::mock::DisplaySurface();
+ mock::NativeWindow* mNativeWindow = new mock::NativeWindow();
+ mock::TimeStats* mTimeStats = new mock::TimeStats();
+ Hwc2::mock::PowerAdvisor* mPowerAdvisor = nullptr;
+ Hwc2::mock::Composer* mComposer = nullptr;
+};
+
+void SurfaceFlingerPowerHintTest::SetUp() {
+ setupScheduler();
+ mComposer = new Hwc2::mock::Composer();
+ mPowerAdvisor = new Hwc2::mock::PowerAdvisor();
+ mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
+ mFlinger.setupTimeStats(std::shared_ptr<TimeStats>(mTimeStats));
+ mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
+ mFlinger.setupPowerAdvisor(std::unique_ptr<Hwc2::PowerAdvisor>(mPowerAdvisor));
+ static constexpr bool kIsPrimary = true;
+ FakeHwcDisplayInjector(DEFAULT_DISPLAY_ID, hal::DisplayType::PHYSICAL, kIsPrimary)
+ .setPowerMode(hal::PowerMode::ON)
+ .inject(&mFlinger, mComposer);
+ auto compostionEngineDisplayArgs =
+ compositionengine::DisplayCreationArgsBuilder()
+ .setId(DEFAULT_DISPLAY_ID)
+ .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT})
+ .setPowerAdvisor(mPowerAdvisor)
+ .setName("injected display")
+ .build();
+ auto compositionDisplay =
+ compositionengine::impl::createDisplay(mFlinger.getCompositionEngine(),
+ std::move(compostionEngineDisplayArgs));
+ mDisplay =
+ FakeDisplayDeviceInjector(mFlinger, compositionDisplay,
+ ui::DisplayConnectionType::Internal, HWC_DISPLAY, kIsPrimary)
+ .setDisplaySurface(mDisplaySurface)
+ .setNativeWindow(mNativeWindow)
+ .setPowerMode(hal::PowerMode::ON)
+ .inject();
+}
+
+void SurfaceFlingerPowerHintTest::setupScheduler() {
+ auto eventThread = std::make_unique<mock::EventThread>();
+ auto sfEventThread = std::make_unique<mock::EventThread>();
+
+ EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*eventThread, createEventConnection(_, _))
+ .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
+ ResyncCallback())));
+
+ EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
+ .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
+ ResyncCallback())));
+
+ auto vsyncController = std::make_unique<mock::VsyncController>();
+ auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
+
+ EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
+ EXPECT_CALL(*vsyncTracker, currentPeriod())
+ .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
+ EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
+
+ mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
+ std::move(eventThread), std::move(sfEventThread),
+ TestableSurfaceFlinger::SchedulerCallbackImpl::kNoOp,
+ TestableSurfaceFlinger::kTwoDisplayModes);
+}
+
+TEST_F(SurfaceFlingerPowerHintTest, sendDurationsIncludingHwcWaitTime) {
+ ON_CALL(*mPowerAdvisor, usePowerHintSession()).WillByDefault(Return(true));
+
+ const std::chrono::nanoseconds mockVsyncPeriod = 15ms;
+ EXPECT_CALL(*mPowerAdvisor, setTargetWorkDuration(_)).Times(1);
+
+ const nsecs_t now = systemTime();
+ const std::chrono::nanoseconds mockHwcRunTime = 20ms;
+ EXPECT_CALL(*mDisplaySurface,
+ prepareFrame(compositionengine::DisplaySurface::CompositionType::Hwc))
+ .Times(1);
+ EXPECT_CALL(*mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _, _))
+ .WillOnce([mockHwcRunTime] {
+ std::this_thread::sleep_for(mockHwcRunTime);
+ return hardware::graphics::composer::V2_1::Error::NONE;
+ });
+ EXPECT_CALL(*mPowerAdvisor,
+ sendActualWorkDuration(Gt(mockHwcRunTime.count()),
+ Gt(now + mockHwcRunTime.count())))
+ .Times(1);
+ static constexpr bool kVsyncId = 123; // arbitrary
+ mFlinger.commitAndComposite(now, kVsyncId, now + mockVsyncPeriod.count());
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
index 7948e60..583cf5f 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
@@ -406,7 +406,7 @@
display.inject();
// The display is set to PowerMode::ON
- getDisplayDevice(display.token())->setPowerMode(PowerMode::ON);
+ display.mutableDisplayDevice()->setPowerMode(PowerMode::ON);
// --------------------------------------------------------------------
// Invocation
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index bf2465f..f1a69fb 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -17,6 +17,7 @@
#pragma once
#include <algorithm>
+#include <chrono>
#include <variant>
#include <compositionengine/Display.h>
@@ -200,6 +201,10 @@
std::make_unique<impl::HWComposer>(std::move(composer)));
}
+ void setupPowerAdvisor(std::unique_ptr<Hwc2::PowerAdvisor> powerAdvisor) {
+ mFlinger->mPowerAdvisor = std::move(powerAdvisor);
+ }
+
void setupTimeStats(const std::shared_ptr<TimeStats>& timeStats) {
mFlinger->mCompositionEngine->setTimeStats(timeStats);
}
@@ -328,11 +333,26 @@
/* ------------------------------------------------------------------------
* Forwarding for functions being tested
*/
+
+ nsecs_t commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVSyncTime) {
+ mFlinger->commit(frameTime, vsyncId, expectedVSyncTime);
+ return frameTime;
+ }
+
+ nsecs_t commit(nsecs_t frameTime, int64_t vsyncId) {
+ std::chrono::nanoseconds period = 10ms;
+ return commit(frameTime, vsyncId, frameTime + period.count());
+ }
+
nsecs_t commit() {
const nsecs_t now = systemTime();
const nsecs_t expectedVsyncTime = now + 10'000'000;
- mFlinger->commit(now, kVsyncId, expectedVsyncTime);
- return now;
+ return commit(now, kVsyncId, expectedVsyncTime);
+ }
+
+ void commitAndComposite(const nsecs_t frameTime, const int64_t vsyncId,
+ const nsecs_t expectedVsyncTime) {
+ mFlinger->composite(commit(frameTime, vsyncId, expectedVsyncTime), kVsyncId);
}
void commitAndComposite() { mFlinger->composite(commit(), kVsyncId); }
@@ -458,11 +478,6 @@
mFlinger->onActiveDisplayChangedLocked(activeDisplay);
}
- auto commit(nsecs_t frameTime, int64_t vsyncId) {
- const nsecs_t expectedVsyncTime = frameTime + 10'000'000;
- mFlinger->commit(frameTime, vsyncId, expectedVsyncTime);
- }
-
auto createLayer(LayerCreationArgs& args, sp<IBinder>* outHandle,
const sp<IBinder>& parentHandle, int32_t* outLayerId,
const sp<Layer>& parentLayer, uint32_t* outTransformHint) {
@@ -502,6 +517,12 @@
* post-conditions.
*/
+ const auto& displays() const { return mFlinger->mDisplays; }
+ const auto& currentState() const { return mFlinger->mCurrentState; }
+ const auto& drawingState() const { return mFlinger->mDrawingState; }
+ const auto& transactionFlags() const { return mFlinger->mTransactionFlags; }
+ const auto& hwcPhysicalDisplayIdMap() const { return getHwComposer().mPhysicalDisplayIdMap; }
+
auto& mutableHasWideColorDisplay() { return SurfaceFlinger::hasWideColorDisplay; }
auto& mutableCurrentState() { return mFlinger->mCurrentState; }
@@ -515,7 +536,6 @@
auto& mutablePhysicalDisplayTokens() { return mFlinger->mPhysicalDisplayTokens; }
auto& mutableTexturePool() { return mFlinger->mTexturePool; }
auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; }
- auto& mutablePowerAdvisor() { return mFlinger->mPowerAdvisor; }
auto& mutableDebugDisableHWC() { return mFlinger->mDebugDisableHWC; }
auto& mutableMaxRenderTargetSize() { return mFlinger->mMaxRenderTargetSize; }
@@ -741,7 +761,9 @@
return mFlinger.mutableCurrentState().displays.valueFor(mDisplayToken);
}
- auto& mutableDisplayDevice() { return mFlinger.mutableDisplays()[mDisplayToken]; }
+ const sp<DisplayDevice>& mutableDisplayDevice() {
+ return mFlinger.mutableDisplays().get(mDisplayToken)->get();
+ }
// If `configs` is nullptr, the injector creates RefreshRateConfigs from the `modes`.
// Otherwise, it uses `configs`, which the caller must create using the same `modes`.
@@ -848,12 +870,14 @@
if (!display->isVirtual()) {
display->setActiveMode(activeModeId);
}
- mFlinger.mutableDisplays().emplace(mDisplayToken, display);
+ mFlinger.mutableDisplays().emplace_or_replace(mDisplayToken, display);
+
mFlinger.mutableCurrentState().displays.add(mDisplayToken, state);
mFlinger.mutableDrawingState().displays.add(mDisplayToken, state);
if (const auto& physical = state.physical) {
- mFlinger.mutablePhysicalDisplayTokens()[physical->id] = mDisplayToken;
+ mFlinger.mutablePhysicalDisplayTokens().emplace_or_replace(physical->id,
+ mDisplayToken);
}
return display;
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index 0ef8456..6ffc039 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -268,8 +268,11 @@
for (size_t i = 0; i < MISSED_FRAMES; i++) {
ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementMissedFrames());
}
+ TimeStats::ClientCompositionRecord record;
+ record.hadClientComposition = true;
+
for (size_t i = 0; i < CLIENT_COMPOSITION_FRAMES; i++) {
- ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionFrames());
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->pushCompositionStrategyState(record));
}
SFTimeStatsGlobalProto globalProto;
@@ -459,19 +462,49 @@
EXPECT_THAT(result, HasSubstr(expectedResult));
}
-TEST_F(TimeStatsTest, canIncreaseClientCompositionReusedFrames) {
+TEST_F(TimeStatsTest, canIncreaseClientCompositionStats) {
// this stat is not in the proto so verify by checking the string dump
- constexpr size_t CLIENT_COMPOSITION_REUSED_FRAMES = 2;
+ constexpr size_t COMPOSITION_STRATEGY_CHANGED_FRAMES = 1;
+ constexpr size_t HAD_CLIENT_COMPOSITION_FRAMES = 2;
+ constexpr size_t REUSED_CLIENT_COMPOSITION_FRAMES = 3;
+ constexpr size_t COMPOSITION_STRATEGY_PREDICTION_SUCCEEDED_FRAMES = 4;
+ constexpr size_t COMPOSITION_STRATEGY_PREDICTED_FRAMES = 5;
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
- for (size_t i = 0; i < CLIENT_COMPOSITION_REUSED_FRAMES; i++) {
- ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionReusedFrames());
+ for (size_t i = 0; i <= COMPOSITION_STRATEGY_PREDICTED_FRAMES; i++) {
+ TimeStats::ClientCompositionRecord record;
+ record.hadClientComposition = i < HAD_CLIENT_COMPOSITION_FRAMES;
+ record.changed = i < COMPOSITION_STRATEGY_CHANGED_FRAMES;
+ record.reused = i < REUSED_CLIENT_COMPOSITION_FRAMES;
+ record.predicted = i < COMPOSITION_STRATEGY_PREDICTED_FRAMES;
+ record.predictionSucceeded = i < COMPOSITION_STRATEGY_PREDICTION_SUCCEEDED_FRAMES;
+ mTimeStats->pushCompositionStrategyState(record);
}
const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
- const std::string expectedResult =
- "clientCompositionReusedFrames = " + std::to_string(CLIENT_COMPOSITION_REUSED_FRAMES);
- EXPECT_THAT(result, HasSubstr(expectedResult));
+ std::string expected =
+ "compositionStrategyChanges = " + std::to_string(COMPOSITION_STRATEGY_CHANGED_FRAMES);
+ EXPECT_THAT(result, HasSubstr(expected));
+
+ expected = "clientCompositionFrames = " + std::to_string(HAD_CLIENT_COMPOSITION_FRAMES);
+ EXPECT_THAT(result, HasSubstr(expected));
+
+ expected =
+ "clientCompositionReusedFrames = " + std::to_string(REUSED_CLIENT_COMPOSITION_FRAMES);
+ EXPECT_THAT(result, HasSubstr(expected));
+
+ expected = "compositionStrategyPredicted = " +
+ std::to_string(COMPOSITION_STRATEGY_PREDICTED_FRAMES);
+ EXPECT_THAT(result, HasSubstr(expected));
+
+ expected = "compositionStrategyPredictionSucceeded = " +
+ std::to_string(COMPOSITION_STRATEGY_PREDICTION_SUCCEEDED_FRAMES);
+ EXPECT_THAT(result, HasSubstr(expected));
+
+ expected = "compositionStrategyPredictionFailed = " +
+ std::to_string(COMPOSITION_STRATEGY_PREDICTED_FRAMES -
+ COMPOSITION_STRATEGY_PREDICTION_SUCCEEDED_FRAMES);
+ EXPECT_THAT(result, HasSubstr(expected));
}
TEST_F(TimeStatsTest, canIncreaseRefreshRateSwitches) {
@@ -489,21 +522,6 @@
EXPECT_THAT(result, HasSubstr(expectedResult));
}
-TEST_F(TimeStatsTest, canIncreaseCompositionStrategyChanges) {
- // this stat is not in the proto so verify by checking the string dump
- constexpr size_t COMPOSITION_STRATEGY_CHANGES = 2;
-
- EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
- for (size_t i = 0; i < COMPOSITION_STRATEGY_CHANGES; i++) {
- ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementCompositionStrategyChanges());
- }
-
- const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
- const std::string expectedResult =
- "compositionStrategyChanges = " + std::to_string(COMPOSITION_STRATEGY_CHANGES);
- EXPECT_THAT(result, HasSubstr(expectedResult));
-}
-
TEST_F(TimeStatsTest, canAverageFrameDuration) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
mTimeStats->setPowerMode(PowerMode::ON);
@@ -836,7 +854,7 @@
ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementTotalFrames());
ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementMissedFrames());
- ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionFrames());
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->pushCompositionStrategyState({}));
ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(PowerMode::ON));
mTimeStats->recordFrameDuration(std::chrono::nanoseconds(3ms).count(),
@@ -867,9 +885,8 @@
TEST_F(TimeStatsTest, canClearDumpOnlyTimeStats) {
// These stats are not in the proto so verify by checking the string dump.
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
- ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionReusedFrames());
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->pushCompositionStrategyState({}));
ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementRefreshRateSwitches());
- ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementCompositionStrategyChanges());
mTimeStats->setPowerMode(PowerMode::ON);
mTimeStats->recordFrameDuration(std::chrono::nanoseconds(1ms).count(),
std::chrono::nanoseconds(5ms).count());
@@ -1032,8 +1049,10 @@
for (size_t i = 0; i < MISSED_FRAMES; i++) {
mTimeStats->incrementMissedFrames();
}
+ TimeStats::ClientCompositionRecord record;
+ record.hadClientComposition = true;
for (size_t i = 0; i < CLIENT_COMPOSITION_FRAMES; i++) {
- mTimeStats->incrementClientCompositionFrames();
+ mTimeStats->pushCompositionStrategyState(record);
}
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index c1d41bb..aa8b521 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -126,7 +126,8 @@
Error(Display, uint64_t, uint64_t, DisplayedFrameStats*));
MOCK_METHOD3(setLayerPerFrameMetadataBlobs,
Error(Display, Layer, const std::vector<IComposerClient::PerFrameMetadataBlob>&));
- MOCK_METHOD3(setDisplayBrightness, Error(Display, float, const DisplayBrightnessOptions&));
+ MOCK_METHOD4(setDisplayBrightness,
+ Error(Display, float, float, const DisplayBrightnessOptions&));
MOCK_METHOD2(
getDisplayCapabilities,
Error(Display,
@@ -151,8 +152,10 @@
const std::vector<uint8_t>&));
MOCK_METHOD1(getLayerGenericMetadataKeys,
V2_4::Error(std::vector<IComposerClient::LayerGenericMetadataKey>*));
- MOCK_METHOD3(getClientTargetProperty,
- Error(Display, IComposerClient::ClientTargetProperty*, float*));
+ MOCK_METHOD2(getClientTargetProperty,
+ Error(Display,
+ aidl::android::hardware::graphics::composer3::
+ ClientTargetPropertyWithBrightness*));
MOCK_METHOD3(setLayerBrightness, Error(Display, Layer, float));
MOCK_METHOD3(setLayerBlockingRegion,
Error(Display, Layer, const std::vector<IComposerClient::Rect>&));
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
index ac2ab199c..3e0d6d3 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
@@ -81,7 +81,7 @@
(nsecs_t, uint32_t *, uint32_t *, android::sp<android::Fence> *, uint32_t *),
(override));
MOCK_METHOD(std::future<hal::Error>, setDisplayBrightness,
- (float, const Hwc2::Composer::DisplayBrightnessOptions &), (override));
+ (float, float, const Hwc2::Composer::DisplayBrightnessOptions &), (override));
MOCK_METHOD(hal::Error, setActiveConfigWithConstraints,
(hal::HWConfigId, const hal::VsyncPeriodChangeConstraints &,
hal::VsyncPeriodChangeTimeline *),
@@ -93,8 +93,10 @@
MOCK_METHOD(hal::Error, getSupportedContentTypes, (std::vector<hal::ContentType> *),
(const, override));
MOCK_METHOD(hal::Error, setContentType, (hal::ContentType), (override));
- MOCK_METHOD(hal::Error, getClientTargetProperty, (hal::ClientTargetProperty *, float *),
- (override));
+ MOCK_METHOD(
+ hal::Error, getClientTargetProperty,
+ (aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness *),
+ (override));
MOCK_METHOD(
hal::Error, getDisplayDecorationSupport,
(std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport> *),
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.cpp b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.cpp
new file mode 100644
index 0000000..2323ebb
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.cpp
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+#include "mock/DisplayHardware/MockIPower.h"
+
+namespace android::Hwc2::mock {
+
+// Explicit default instantiation is recommended.
+MockIPower::MockIPower() = default;
+
+} // namespace android::Hwc2::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.h
new file mode 100644
index 0000000..0ddc90d
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "binder/Status.h"
+
+#include <android/hardware/power/IPower.h>
+#include <gmock/gmock.h>
+
+using android::binder::Status;
+using android::hardware::power::Boost;
+using android::hardware::power::IPower;
+using android::hardware::power::IPowerHintSession;
+using android::hardware::power::Mode;
+
+namespace android::Hwc2::mock {
+
+class MockIPower : public IPower {
+public:
+ MockIPower();
+
+ MOCK_METHOD(Status, isBoostSupported, (Boost boost, bool* ret), (override));
+ MOCK_METHOD(Status, setBoost, (Boost boost, int32_t durationMs), (override));
+ MOCK_METHOD(Status, isModeSupported, (Mode mode, bool* ret), (override));
+ MOCK_METHOD(Status, setMode, (Mode mode, bool enabled), (override));
+ MOCK_METHOD(Status, createHintSession,
+ (int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds,
+ int64_t durationNanos, sp<IPowerHintSession>* session),
+ (override));
+ MOCK_METHOD(Status, getHintSessionPreferredRate, (int64_t * rate), (override));
+ MOCK_METHOD(int32_t, getInterfaceVersion, (), (override));
+ MOCK_METHOD(std::string, getInterfaceHash, (), (override));
+ MOCK_METHOD(IBinder*, onAsBinder, (), (override));
+};
+
+} // namespace android::Hwc2::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.cpp b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.cpp
new file mode 100644
index 0000000..770bc15
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.cpp
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+#include "mock/DisplayHardware/MockIPowerHintSession.h"
+
+namespace android::Hwc2::mock {
+
+// Explicit default instantiation is recommended.
+MockIPowerHintSession::MockIPowerHintSession() = default;
+
+} // namespace android::Hwc2::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h
new file mode 100644
index 0000000..439f6f4
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "binder/Status.h"
+
+#include <android/hardware/power/IPower.h>
+#include <gmock/gmock.h>
+
+using android::binder::Status;
+using android::hardware::power::IPowerHintSession;
+
+using namespace android::hardware::power;
+
+namespace android::Hwc2::mock {
+
+class MockIPowerHintSession : public IPowerHintSession {
+public:
+ MockIPowerHintSession();
+
+ MOCK_METHOD(IBinder*, onAsBinder, (), (override));
+ MOCK_METHOD(Status, pause, (), (override));
+ MOCK_METHOD(Status, resume, (), (override));
+ MOCK_METHOD(Status, close, (), (override));
+ MOCK_METHOD(int32_t, getInterfaceVersion, (), (override));
+ MOCK_METHOD(std::string, getInterfaceHash, (), (override));
+ MOCK_METHOD(Status, updateTargetWorkDuration, (int64_t), (override));
+ MOCK_METHOD(Status, reportActualWorkDuration, (const ::std::vector<WorkDuration>&), (override));
+};
+
+} // namespace android::Hwc2::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
index 0a69b56..0dee800 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -33,10 +33,7 @@
MOCK_METHOD0(miniDump, std::string());
MOCK_METHOD0(incrementTotalFrames, void());
MOCK_METHOD0(incrementMissedFrames, void());
- MOCK_METHOD0(incrementClientCompositionFrames, void());
- MOCK_METHOD0(incrementClientCompositionReusedFrames, void());
MOCK_METHOD0(incrementRefreshRateSwitches, void());
- MOCK_METHOD0(incrementCompositionStrategyChanges, void());
MOCK_METHOD1(recordDisplayEventConnectionCount, void(int32_t));
MOCK_METHOD2(recordFrameDuration, void(nsecs_t, nsecs_t));
MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, nsecs_t));
@@ -63,6 +60,8 @@
void(hardware::graphics::composer::V2_4::IComposerClient::PowerMode));
MOCK_METHOD2(recordRefreshRate, void(uint32_t, nsecs_t));
MOCK_METHOD1(setPresentFenceGlobal, void(const std::shared_ptr<FenceTime>&));
+ MOCK_METHOD(void, pushCompositionStrategyState,
+ (const android::TimeStats::ClientCompositionRecord&), (override));
};
} // namespace android::mock
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 45bc4c9..c4b1487 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -299,6 +299,7 @@
}
void ReleaseSwapchainImage(VkDevice device,
+ bool shared_present,
ANativeWindow* window,
int release_fence,
Swapchain::Image& image,
@@ -330,7 +331,8 @@
}
image.dequeue_fence = -1;
- if (window) {
+ // It's invalid to call cancelBuffer on a shared buffer
+ if (window && !shared_present) {
window->cancelBuffer(window, image.buffer.get(), release_fence);
} else {
if (release_fence >= 0) {
@@ -364,9 +366,10 @@
if (swapchain->surface.swapchain_handle != HandleFromSwapchain(swapchain))
return;
for (uint32_t i = 0; i < swapchain->num_images; i++) {
- if (!swapchain->images[i].dequeued)
- ReleaseSwapchainImage(device, nullptr, -1, swapchain->images[i],
- true);
+ if (!swapchain->images[i].dequeued) {
+ ReleaseSwapchainImage(device, swapchain->shared, nullptr, -1,
+ swapchain->images[i], true);
+ }
}
swapchain->surface.swapchain_handle = VK_NULL_HANDLE;
swapchain->timing.clear();
@@ -1084,7 +1087,8 @@
}
for (uint32_t i = 0; i < swapchain->num_images; i++) {
- ReleaseSwapchainImage(device, window, -1, swapchain->images[i], false);
+ ReleaseSwapchainImage(device, swapchain->shared, window, -1,
+ swapchain->images[i], false);
}
if (active) {
@@ -1854,7 +1858,8 @@
WorstPresentResult(swapchain_result, VK_SUBOPTIMAL_KHR);
}
} else {
- ReleaseSwapchainImage(device, nullptr, fence, img, true);
+ ReleaseSwapchainImage(device, swapchain.shared, nullptr, fence,
+ img, true);
swapchain_result = VK_ERROR_OUT_OF_DATE_KHR;
}